diff options
-rw-r--r-- | NEWS | 9 | ||||
-rw-r--r-- | macros/neon.m4 | 6 | ||||
-rw-r--r-- | src/ne_auth.c | 4 | ||||
-rw-r--r-- | src/ne_basic.c | 12 | ||||
-rw-r--r-- | src/ne_compress.c | 30 | ||||
-rw-r--r-- | src/ne_openssl.c | 2 | ||||
-rw-r--r-- | src/ne_private.h | 3 | ||||
-rw-r--r-- | src/ne_request.c | 16 | ||||
-rw-r--r-- | src/ne_xml.c | 2 | ||||
-rw-r--r-- | test/compress.c | 60 |
10 files changed, 119 insertions, 25 deletions
@@ -1,3 +1,12 @@ +Changes in release 0.25.1: +* ne_get_content_type(): fix cases where the charset field was not set + to NULL after successful return (Johannes Schneider) +* Compressed response handling fixes: + - fix double invocation of reader callback with len=0 + - fix cases where the reader callback return value was ignored +* Cache the new SSL session if the old one was expired (Robert Eiglmaier) +* Win32: fix build issues. + Changes in release 0.25.0: * New interfaces: - ne_get_response_header() replaces ne_add_response_header_handler diff --git a/macros/neon.m4 b/macros/neon.m4 index a19c1e7..aae2ea0 100644 --- a/macros/neon.m4 +++ b/macros/neon.m4 @@ -136,9 +136,9 @@ AC_DEFUN([NE_VERSIONS_BUNDLED], [ # Define the current versions. NE_VERSION_MAJOR=0 -NE_VERSION_MINOR=26 -NE_VERSION_PATCH=0 -NE_VERSION_TAG=-dev +NE_VERSION_MINOR=25 +NE_VERSION_PATCH=1 +NE_VERSION_TAG= # libtool library interface versioning. Release policy dictates that # for neon 0.x.y, each x brings an incompatible interface change, and diff --git a/src/ne_auth.c b/src/ne_auth.c index ff2e280..480968c 100644 --- a/src/ne_auth.c +++ b/src/ne_auth.c @@ -1210,8 +1210,6 @@ static void ah_pre_send(ne_request *r, void *cookie, ne_buffer *request) } -#define SAFELY(x) ((x) != NULL?(x):"null") - static int ah_post_send(ne_request *req, void *cookie, const ne_status *status) { auth_session *sess = cookie; @@ -1242,7 +1240,7 @@ static int ah_post_send(ne_request *req, void *cookie, const ne_status *status) NE_DEBUG(NE_DBG_HTTPAUTH, "ah_post_send (#%d), code is %d (want %d), %s is %s\n", sess->attempt, status->code, sess->spec->status_code, - sess->spec->resp_hdr, auth_hdr); + sess->spec->resp_hdr, auth_hdr ? auth_hdr : "(none)"); if (auth_info_hdr && sess->scheme == auth_scheme_digest) { if (verify_digest_response(areq, sess, auth_info_hdr)) { NE_DEBUG(NE_DBG_HTTPAUTH, "Response authentication invalid.\n"); diff --git a/src/ne_basic.c b/src/ne_basic.c index de210e9..e50138c 100644 --- a/src/ne_basic.c +++ b/src/ne_basic.c @@ -239,20 +239,18 @@ int ne_get_content_type(ne_request *req, ne_content_type *ct) return -1; } - ct->value = ne_strdup(value); - - stype = strchr(ct->value, '/'); + ct->type = ct->value = ne_strdup(value); + stype = strchr(ct->value, '/'); *stype++ = '\0'; - ct->type = ct->value; ct->charset = NULL; sep = strchr(stype, ';'); if (sep) { char *tok; - /* look for the charset parameter. TODO; probably better to - * hand-carve a parser than use ne_token/strstr/shave here. */ + + /* Look for the charset parameter: */ *sep++ = '\0'; do { tok = ne_qtoken(&sep, ';', "\"\'"); @@ -270,7 +268,7 @@ int ne_get_content_type(ne_request *req, ne_content_type *ct) ct->subtype = ne_shave(stype, " \t"); if (ct->charset == NULL && strcasecmp(ct->type, "text") == 0) { - /* 3280§3.1: text/xml without charset implies us-ascii. */ + /* 3023§3.1: text/xml without charset implies us-ascii. */ if (strcasecmp(ct->subtype, "xml") == 0) ct->charset = "us-ascii"; /* 2616§3.7.1: subtypes of text/ default to charset ISO-8859-1. */ diff --git a/src/ne_compress.c b/src/ne_compress.c index b36d384..bd614ff 100644 --- a/src/ne_compress.c +++ b/src/ne_compress.c @@ -1,6 +1,6 @@ /* Handling of compressed HTTP responses - Copyright (C) 2001-2004, Joe Orton <joe@manyfish.co.uk> + Copyright (C) 2001-2005, Joe Orton <joe@manyfish.co.uk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -33,6 +33,8 @@ #include "ne_utils.h" #include "ne_i18n.h" +#include "ne_private.h" + #ifdef NE_HAVE_ZLIB #include <zlib.h> @@ -152,8 +154,6 @@ static int process_footer(ne_decompress *ctx, uLong crc = BUF2UINT(ctx->footer) & 0xFFFFFFFF; if (crc == ctx->checksum) { ctx->state = NE_Z_FINISHED; - /* reader requires a size=0 call at end-of-response */ - ctx->reader(ctx->userdata, NULL, 0); NE_DEBUG(NE_DBG_HTTP, "compress: End of response; checksum match.\n"); } else { NE_DEBUG(NE_DBG_HTTP, "compress: End of response; checksum mismatch: " @@ -218,7 +218,9 @@ static int do_inflate(ne_decompress *ctx, const char *buf, size_t len) /* pass on the inflated data, if any */ if (ctx->zstr.total_out > 0) { - ctx->reader(ctx->userdata, ctx->outbuf, ctx->zstr.total_out); + int rret = ctx->reader(ctx->userdata, ctx->outbuf, + ctx->zstr.total_out); + if (rret) return rret; } } while (ret == Z_OK && ctx->zstr.avail_in > 0); @@ -372,6 +374,21 @@ static int gz_reader(void *ud, const char *buf, size_t len) return 0; } +/* Prepare for a compressed response */ +static void gz_pre_send(ne_request *r, void *ud, ne_buffer *req) +{ + ne_decompress *ctx = ud; + + NE_DEBUG(NE_DBG_HTTP, "compress: Initialization.\n"); + + /* (Re-)Initialize the context */ + ctx->state = NE_Z_BEFORE_DATA; + if (ctx->zstrinit) inflateEnd(&ctx->zstr); + ctx->zstrinit = 0; + ctx->hdrcount = ctx->footcount = 0; + ctx->checksum = crc32(0L, Z_NULL, 0); +} + void ne_decompress_destroy(ne_decompress *ctx) { if (ctx->zstrinit) @@ -398,15 +415,14 @@ ne_decompress *ne_decompress_reader(ne_request *req, ne_accept_response acpt, ne_add_response_body_reader(req, gz_acceptor, gz_reader, ctx); - ctx->state = NE_Z_BEFORE_DATA; ctx->reader = rdr; ctx->userdata = userdata; ctx->session = ne_get_session(req); ctx->request = req; - /* initialize the checksum. */ - ctx->checksum = crc32(0L, Z_NULL, 0); ctx->acceptor = acpt; + ne__reqhook_pre_send(req, gz_pre_send, ctx); + return ctx; } diff --git a/src/ne_openssl.c b/src/ne_openssl.c index 984626b..f997ef9 100644 --- a/src/ne_openssl.c +++ b/src/ne_openssl.c @@ -302,7 +302,7 @@ static int check_identity(const char *hostname, X509 *cert, char **identity) } while (idx >= 0); if (lastidx < 0) { - /* no commonName attributes at all. */ + /* no commonNmae attributes at all. */ ne_buffer_destroy(cname); return -1; } diff --git a/src/ne_private.h b/src/ne_private.h index a0c4eb0..f5ef345 100644 --- a/src/ne_private.h +++ b/src/ne_private.h @@ -114,4 +114,7 @@ typedef int (*ne_push_fn)(void *userdata, const char *buf, size_t count); /* Do the SSL negotiation. */ int ne__negotiate_ssl(ne_request *req); +/* Hack to fix ne_compress layer problems */ +void ne__reqhook_pre_send(ne_request *sess, ne_pre_send_fn fn, void *userdata); + #endif /* HTTP_PRIVATE_H */ diff --git a/src/ne_request.c b/src/ne_request.c index b98a53b..01f4fa2 100644 --- a/src/ne_request.c +++ b/src/ne_request.c @@ -171,7 +171,7 @@ struct ne_request_s { ne_off_t progress; /* number of bytes read of response */ } resp; - struct hook *private; + struct hook *private, *pre_send_hooks; /* response header fields */ struct field *response_headers[HH_HASHSIZE]; @@ -322,6 +322,12 @@ void ne_hook_destroy_session(ne_session *sess, ADD_HOOK(sess->destroy_sess_hooks, fn, userdata); } +/* Hack to fix ne_compress layer problems */ +void ne__reqhook_pre_send(ne_request *req, ne_pre_send_fn fn, void *userdata) +{ + ADD_HOOK(req->pre_send_hooks, fn, userdata); +} + void ne_set_session_private(ne_session *sess, const char *id, void *userdata) { add_hook(&sess->private, id, NULL, userdata); @@ -734,6 +740,10 @@ void ne_request_destroy(ne_request *req) next_hk = hk->next; ne_free(hk); } + for (hk = req->pre_send_hooks; hk; hk = next_hk) { + next_hk = hk->next; + ne_free(hk); + } if (req->status.reason_phrase) ne_free(req->status.reason_phrase); @@ -887,6 +897,10 @@ static ne_buffer *build_request(ne_request *req) ne_pre_send_fn fn = (ne_pre_send_fn)hk->fn; fn(req, hk->userdata, buf); } + for (hk = req->pre_send_hooks; hk!=NULL; hk = hk->next) { + ne_pre_send_fn fn = (ne_pre_send_fn)hk->fn; + fn(req, hk->userdata, buf); + } ne_buffer_append(buf, "\r\n", 2); return buf; diff --git a/src/ne_xml.c b/src/ne_xml.c index 16c8480..cf6b1ab 100644 --- a/src/ne_xml.c +++ b/src/ne_xml.c @@ -393,7 +393,7 @@ static void end_element(void *userdata, const ne_xml_char *name) } } - NE_DEBUG(NE_DBG_XMLPARSE, "XML: end-element (%d, {%s, %s})\n", + NE_DEBUG(NE_DBG_XML, "XML: end-element (%d, {%s, %s})\n", elm->state, elm->nspace, elm->name); /* move back up the tree */ diff --git a/test/compress.c b/test/compress.c index f40db15..8eadf23 100644 --- a/test/compress.c +++ b/test/compress.c @@ -1,6 +1,6 @@ /* tests for compressed response handling. - Copyright (C) 2001-2004, Joe Orton <joe@manyfish.co.uk> + Copyright (C) 2001-2005, Joe Orton <joe@manyfish.co.uk> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -58,6 +58,14 @@ static int reader(void *ud, const char *block, size_t len) if (failed == f_mismatch) return -1; + /* catch multiple len == 0 call as issued by 0.25.0 only: */ + if (failed == f_complete) { + NE_DEBUG(NE_DBG_HTTP, "reader: called after complete, len=%d\n", + (int)len); + failed = f_mismatch; + return -1; + } + if (failed == f_partial && len == 0) { if (b->len != 0) { NE_DEBUG(NE_DBG_HTTP, "reader: got length %d at EOF\n", @@ -357,6 +365,7 @@ static int retry_accept(void *ud, ne_request *req, const ne_status *st) } expect->len = 5; + failed = f_partial; /* reset the state */ return 1; } @@ -369,6 +378,52 @@ static int retry_compress(void) return retry_compress_helper(retry_accept, &resp, &expect); } +#define READER_ABORT_ERR "reader_abort error string" + +static int reader_abort(void *ud, const char *buf, size_t len) +{ + ne_session *sess = ud; + ne_set_error(sess, READER_ABORT_ERR); + return len; +} + +/* check that a callback abort does abort the response */ +static int compress_abort(void) +{ + ne_session *sess; + ne_request *req; + struct serve_file_args sfargs; + ne_decompress *dc; + int ret; + + sfargs.fname = "file1.gz"; + sfargs.headers = "Content-Encoding: gzip\r\n"; + sfargs.chunks = 0; + + CALL(make_session(&sess, serve_file, &sfargs)); + + req = ne_request_create(sess, "GET", "/abort"); + + dc = ne_decompress_reader(req, ne_accept_2xx, reader_abort, sess); + + ret = ne_request_dispatch(req); + + reap_server(); + + ONN("request was not aborted", ret != NE_ERROR); + ONV(strcmp(ne_get_error(sess), READER_ABORT_ERR), + ("session error was %s not %s", + ne_get_error(sess), READER_ABORT_ERR)); + + reap_server(); + ne_decompress_destroy(dc); + ne_request_destroy(req); + ne_session_destroy(sess); + + return OK; + +} + ne_test tests[] = { T_LEAKY(init), T(not_compressed), @@ -389,6 +444,7 @@ ne_test tests[] = { T(chunked_10b), T(chunked_10b_wn), T(retry_notcompress), - T_XFAIL(retry_compress), + T(retry_compress), + T(compress_abort), T(NULL) }; |