Skip to content
This repository has been archived by the owner on Apr 22, 2019. It is now read-only.

Commit

Permalink
Receive gzip and deflate encoded responce
Browse files Browse the repository at this point in the history
  • Loading branch information
OlehKulykov committed Jun 15, 2016
1 parent eb77b76 commit 0eaa1b5
Show file tree
Hide file tree
Showing 15 changed files with 205 additions and 63 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ set(CPACK_PACKAGE_VERSION_MINOR "3")
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}")
set(CPACK_PACKAGE_VENDOR "[email protected]")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE} ${PACKAGE_VERSION}")
set(SOVERSION "0.3.2")
set(SOVERSION "0.3.3")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
set(VERSION "${CPACK_PACKAGE_VERSION}")

Expand Down
24 changes: 12 additions & 12 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 0.3.2.{build}
version: 0.3.3.{build}


os: Visual Studio 2015
Expand Down Expand Up @@ -110,14 +110,14 @@ artifacts:
- path: '*.7z'


#deploy:
# - provider: GitHub
# release: $(appveyor_build_version)
# description: 'Appveyor CI build artifacts. Compressed install path with binaries, libraries and configured headers'
# auth_token:
# secure: 9fCOXiEygRERkV9JN67Rqq6WFwdbSBIllYdZGYcSoFPj1oUAxk3aRi+bWv04l7M5
# artifact: /.*\.7z/
# draft: false
# prerelease: true
# on:
# branch: master
deploy:
- provider: GitHub
release: $(appveyor_build_version)
description: 'Appveyor CI build artifacts. Compressed install path with binaries, libraries and configured headers'
auth_token:
secure: 9fCOXiEygRERkV9JN67Rqq6WFwdbSBIllYdZGYcSoFPj1oUAxk3aRi+bWv04l7M5
artifact: /.*\.7z/
draft: false
prerelease: true
on:
branch: master
10 changes: 9 additions & 1 deletion libnhr.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

#define NHR_VERSION_MAJOR 0
#define NHR_VERSION_MINOR 3
#define NHR_VERSION_PATCH 2
#define NHR_VERSION_PATCH 3


// check windows
Expand Down Expand Up @@ -216,6 +216,14 @@ NHR_EXTERN const char * k_nhr_content_encoding;
NHR_EXTERN const char * k_nhr_gzip_deflate;


/// String constant "gzip"
NHR_EXTERN const char * k_nhr_gzip;


/// String constant "deflate"
NHR_EXTERN const char * k_nhr_deflate;


// request

/**
Expand Down
2 changes: 2 additions & 0 deletions src/nhr_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const char * k_nhr_application_x_www_form_urlencoded = "application/x-www-form-u
const char * k_nhr_transfer_encoding = "Transfer-Encoding";
const char * k_nhr_content_encoding = "Content-Encoding";
const char * k_nhr_gzip_deflate = "gzip, deflate";
const char * k_nhr_gzip = "gzip";
const char * k_nhr_deflate = "deflate";
const char * k_nhr_CRLF = "\r\n";
const char * k_nhr_double_CRLF = "\r\n\r\n";
const char * k_nhr_content_length = "Content-Length";
Expand Down
3 changes: 3 additions & 0 deletions src/nhr_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,8 @@ NHR_EXTERN const char * k_nhr_content_length; // "Content-Length";
NHR_EXTERN const char * k_nhr_chunked; // "chunked"
#define k_nhr_chunked_length 7

#define k_nhr_gzip_length 4
#define k_nhr_deflate_length 7

#endif

58 changes: 46 additions & 12 deletions src/nhr_gz.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,30 @@ void * nhr_gz_write_footer(void * buff,
void * nhr_gz_compress(const void * buff,
const size_t buff_size,
size_t * compressed_size,
const unsigned char have_header) {
const unsigned char method) {
if (!buff || buff_size == 0) return NULL;

z_stream zip;
void * out_buff = NULL;
size_t writed = 0, out_size = NHR_GZ_CHUNK_SIZE;

memset(&zip, 0, sizeof(z_stream));
int result = deflateInit2(&zip, Z_BEST_COMPRESSION, Z_DEFLATED, NHR_GZ_WINDOWS_BITS, 8, Z_DEFAULT_STRATEGY);

int result = Z_ERRNO;
switch (method) {
case NHR_GZ_METHOD_GZIP:
result = deflateInit2(&zip, Z_BEST_COMPRESSION, Z_DEFLATED, NHR_GZ_WINDOWS_BITS, 8, Z_DEFAULT_STRATEGY);
break;
case NHR_GZ_METHOD_DEFLATE:
result = deflateInit(&zip, Z_BEST_COMPRESSION);
break;
default:
break;
}

if (result != Z_OK) return NULL;

if (have_header) {
if (method == NHR_GZ_METHOD_GZIP) {
out_size += NHR_GZ_HEADER_SIZE;
out_buff = nhr_malloc(out_size);
nhr_gz_write_header(out_buff);
Expand Down Expand Up @@ -140,7 +152,7 @@ void * nhr_gz_compress(const void * buff,
}

writed = zip.total_out; // write total from zip stream
if (have_header) {
if (method == NHR_GZ_METHOD_GZIP) {
writed += NHR_GZ_HEADER_SIZE;
out_buff = nhr_gz_write_footer(out_buff, out_size, writed, buff, buff_size);
writed += NHR_GZ_FOOTER_SIZE;
Expand All @@ -152,28 +164,50 @@ void * nhr_gz_compress(const void * buff,
return out_buff;
}

int nhr_gz_is_gzip_file(const unsigned char * buff, const size_t buff_size) {
if (buff_size <= NHR_GZ_HEADER_SIZE + NHR_GZ_FOOTER_SIZE) return 0;
return buff[0] == 0x1f && buff[1] == 0x8b;
}

void * nhr_gz_decompress(const void * buff,
const size_t buff_size,
size_t * decompressed_size,
const unsigned char have_header) {
const unsigned char method) {
//TODO: process gz header
if (!buff || buff_size == 0) return NULL;

z_stream zip;
memset(&zip, 0, sizeof(z_stream));
void * out_buff = nhr_malloc(NHR_GZ_CHUNK_SIZE);
void * out_buff = NULL;
size_t out_size = NHR_GZ_CHUNK_SIZE;
size_t writed = 0;

int available_size = 0;

int result = inflateInit2(&zip, NHR_GZ_WINDOWS_BITS);
if (result != Z_OK) {
nhr_free(out_buff);
return NULL;
// The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller.

int result = Z_ERRNO;
switch (method) {
case NHR_GZ_METHOD_GZIP:
if (nhr_gz_is_gzip_file(buff, buff_size)) {
zip.avail_in = (uInt)buff_size - NHR_GZ_HEADER_SIZE - NHR_GZ_FOOTER_SIZE;
zip.next_in = (Bytef *)buff + NHR_GZ_HEADER_SIZE;
result = inflateInit2(&zip, NHR_GZ_WINDOWS_BITS);
}
break;
case NHR_GZ_METHOD_DEFLATE:
zip.avail_in = (uInt)buff_size;
zip.next_in = (Bytef *)buff;
result = inflateInit(&zip);
break;
default:
break;
}

zip.avail_in = (uInt)buff_size;
zip.next_in = (Bytef *)buff;
if (result != Z_OK) return NULL;

out_buff = nhr_malloc(NHR_GZ_CHUNK_SIZE);

zip.avail_out = NHR_GZ_CHUNK_SIZE;

do {
Expand Down
9 changes: 7 additions & 2 deletions src/nhr_gz.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,20 @@

#if defined(NHR_GZIP)

// raw deflate

#define NHR_GZ_METHOD_DEFLATE 0
#define NHR_GZ_METHOD_GZIP 1

void * nhr_gz_compress(const void * buff,
const size_t buff_size,
size_t * compressed_size,
const unsigned char have_header);
const unsigned char method);

void * nhr_gz_decompress(const void * buff,
const size_t buff_size,
size_t * decompressed_size,
const unsigned char have_header);
const unsigned char method);

#endif
#endif
4 changes: 3 additions & 1 deletion src/nhr_request_private.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ nhr_bool nhr_request_recv(_nhr_request * r) {
}

void nhr_request_wait_raw_responce(_nhr_request * r) {
nhr_bool is_finished = nhr_false;
if (nhr_request_recv(r)) {
if (nhr_response_is_finished(r->responce)) nhr_request_set_command(r, NHR_COMMAND_INFORM_RESPONCE);
is_finished = r->responce ? r->responce->is_finished : nhr_false;
if (is_finished) nhr_request_set_command(r, NHR_COMMAND_INFORM_RESPONCE);
if (!nhr_request_check_timeout(r)) return; // error already exists
} else if (r) {
nhr_request_set_command(r, NHR_COMMAND_INFORM_RESPONCE);
Expand Down
110 changes: 85 additions & 25 deletions src/nhr_response.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,31 @@
#include "nhr_response.h"
#include "nhr_memory.h"
#include "nhr_string.h"
#include "nhr_gz.h"
#include <string.h>
#include <ctype.h>

#if defined(NHR_GZIP)
void nhr_response_ungzip(_nhr_response * r) {
if (!r->body || r->body_len <= 0) return;

void * decompressed = NULL;
size_t decompressed_size = 0;
if (r->content_encoding & NHR_CONTENT_ENCODING_GZIP) {
decompressed = nhr_gz_decompress(r->body, r->body_len, &decompressed_size, NHR_GZ_METHOD_GZIP);
} else if (r->content_encoding & NHR_CONTENT_ENCODING_DEFLATE) {
decompressed = nhr_gz_decompress(r->body, r->body_len, &decompressed_size, NHR_GZ_METHOD_DEFLATE);
}
if (decompressed && decompressed_size > 0) {
nhr_free(r->body);
r->body = decompressed;
r->body_len = decompressed_size;
} else {
nhr_free(decompressed);
}
}
#endif

void nhr_response_fix_body_len(_nhr_response * r) {
if (r->content_length > 0 && r->body_len > r->content_length) {
// some trash was copyed, ignore it.
Expand Down Expand Up @@ -64,7 +86,12 @@ void nhr_response_read_chunks(_nhr_response * r, char * str) {
#endif

void nhr_response_parse_body(_nhr_response * r, char * received, const size_t received_len) {
// printf("\n------HEADER---------\n%s\n---------------------\n", received);
#if defined(NHR_DEBUG_LOG)
size_t log_index = 0;
printf("\n----[ RESPONCE HEADER ]----\n");
for (log_index = 0; log_index < received_len; log_index++) printf("%c", received[log_index]);
printf("\n---------------------------\n");
#endif
char * sub = strstr(received, k_nhr_double_CRLF);
if (!sub) return;

Expand All @@ -73,7 +100,7 @@ void nhr_response_parse_body(_nhr_response * r, char * received, const size_t re
sub += k_nhr_double_CRLF_length;
skiped -= k_nhr_double_CRLF_length;

if (r->transfer_encoding == NHR_TRANSFER_ENCODING_CHUNKED) {
if (r->transfer_encoding & NHR_TRANSFER_ENCODING_CHUNKED) {
#if !defined(NHR_NO_CHUNKED)
nhr_response_read_chunks(r, sub);
#endif
Expand Down Expand Up @@ -103,30 +130,74 @@ void nhr_response_parse_content_length(_nhr_response * r, char * received) {
if (nhr_sscanf(value, "%lu", &length) == 1 && length > 0) r->content_length = (size_t)length;
}

void nhr_response_log_unprocessed(const char * key, const char * value) {
printf("\nWARNING: libnhr unprocessed \"%s\" : \"%s\".", key, value);
}

void nhr_response_parse_transfer_encoding(_nhr_response * r, char * received) {
char * sub = nhr_response_find_http_field_value(received, k_nhr_transfer_encoding);
if (!sub) return;
char * encoding = nhr_response_find_http_field_value(received, k_nhr_transfer_encoding);
if (!encoding) return;

if (strncmp(sub, k_nhr_chunked, k_nhr_chunked_length) == 0) {
if (strstr(encoding, k_nhr_chunked)) {
#if defined(NHR_NO_CHUNKED)
printf("WARNING: libnhr unprocessed chucked encoding.\n");
nhr_response_log_unprocessed(k_nhr_transfer_encoding, encoding);
#else
r->transfer_encoding = NHR_TRANSFER_ENCODING_CHUNKED;
r->transfer_encoding |= NHR_TRANSFER_ENCODING_CHUNKED;
#endif
}
}

void nhr_response_parse_content_encoding(_nhr_response * r, char * received) {
char * encoding = nhr_response_find_http_field_value(received, k_nhr_content_encoding);
if (!encoding) return;

if (strstr(encoding, k_nhr_gzip)) {
#if defined(NHR_GZIP)
r->content_encoding |= NHR_CONTENT_ENCODING_GZIP;
#else
nhr_response_log_unprocessed(k_nhr_transfer_encoding, encoding);
#endif
}
if (strstr(encoding, k_nhr_deflate)) {
#if defined(NHR_GZIP)
r->content_encoding |= NHR_CONTENT_ENCODING_DEFLATE;
#else
nhr_response_log_unprocessed(k_nhr_transfer_encoding, encoding);
#endif
}
}

nhr_bool nhr_response_is_finished_receiving(_nhr_response * r) {
#if !defined(NHR_NO_CHUNKED)
if (r->transfer_encoding & NHR_TRANSFER_ENCODING_CHUNKED) return r->is_all_chunks_processed;
#endif
return (r->content_length > 0) ? r->content_length == r->body_len : nhr_false;
}

void nhr_response_check_is_finished(_nhr_response * r) {
if (!nhr_response_is_finished_receiving(r)) return;

if (r->content_encoding & NHR_CONTENT_ENCODING_GZIP ||
r->content_encoding & NHR_CONTENT_ENCODING_DEFLATE) {
#if defined(NHR_GZIP)
nhr_response_ungzip(r);
#endif
}
r->is_finished = nhr_true;
}

_nhr_response * nhr_response_create(void * received, const size_t received_len) {
_nhr_response * r = (_nhr_response *)nhr_malloc_zero(sizeof(struct _nhr_response_struct));

nhr_response_parse_status_code(r, (char *)received);
nhr_response_parse_status_code(r, received);

if (r->status_code == 200) {
nhr_response_parse_content_length(r, (char *)received);
nhr_response_parse_transfer_encoding(r, (char *)received);
nhr_response_parse_body(r, (char *)received, received_len);
nhr_response_parse_content_length(r, received);
nhr_response_parse_transfer_encoding(r, received);
nhr_response_parse_content_encoding(r, received);
nhr_response_parse_body(r, received, received_len);
}

nhr_response_check_is_finished(r);
return r;
}

Expand All @@ -149,13 +220,14 @@ void nhr_response_add_body_data(_nhr_response * r, void * data, const size_t dat
}

void nhr_response_append(_nhr_response * r, void * received, const size_t received_len) {
if (r->transfer_encoding == NHR_TRANSFER_ENCODING_CHUNKED) {
if (r->transfer_encoding & NHR_TRANSFER_ENCODING_CHUNKED) {
#if !defined(NHR_NO_CHUNKED)
nhr_response_read_chunks(r, (char *)received);
#endif
} else {
nhr_response_add_body_data(r, received, received_len);
}
nhr_response_check_is_finished(r);
}

void nhr_response_delete(_nhr_response * r) {
Expand All @@ -180,15 +252,3 @@ unsigned int nhr_response_get_body_length(nhr_response responce) {
_nhr_response * r = (_nhr_response *)responce;
return r ? (unsigned int)r->body_len : 0;
}

nhr_bool nhr_response_is_finished(_nhr_response * r) {
if (!r) return nhr_false;

#if !defined(NHR_NO_CHUNKED)
if (r->transfer_encoding == NHR_TRANSFER_ENCODING_CHUNKED) {
return r->is_all_chunks_processed;
}
#endif

return (r->content_length > 0) ? r->content_length == r->body_len : nhr_false;
}
Loading

0 comments on commit 0eaa1b5

Please sign in to comment.