--- neon-0.24.7/src/ne_request.c.ark 2004-12-27 14:11:20.000000000 +0100 +++ neon-0.24.7/src/ne_request.c 2004-12-27 14:26:37.000000000 +0100 @@ -110,6 +110,8 @@ size_t body_size, body_progress; + int chunked; /* Send request incrementally chunked */ + /* temporary store for response lines. */ char respbuf[BUFSIZ]; @@ -445,6 +447,29 @@ return ret; } +int ne_send_request_chunk(ne_request *req, const char *buffer, size_t size) +{ + char chunksize[20]; + int ret; + + ne_snprintf(chunksize, sizeof chunksize, "%x%s", size, EOL); + chunksize[sizeof(chunksize)-1] = '\0'; + + ret = ne_sock_fullwrite(req->session->socket, chunksize, strlen(chunksize)); + + if (!ret && size > 0) + ret = ne_sock_fullwrite(req->session->socket, buffer, size); + + if (!ret) + ret = ne_sock_fullwrite(req->session->socket, EOL, sizeof(EOL)-1); + + /* XXX Final EOL on last 0 byte chunk? perhaps call ne_finish_request? */ + if (!ret && size == 0) + ret = ne_sock_fullwrite(req->session->socket, EOL, sizeof(EOL)-1); + + return ret; +} + /* Lob the User-Agent, connection and host headers in to the request * headers */ static void add_fixed_headers(ne_request *req) @@ -583,6 +608,11 @@ set_body_size(req, bodysize); } +void ne_set_request_chunked(ne_request *req, int chunked) +{ + req->chunked = chunked; +} + int ne_set_request_body_fd(ne_request *req, int fd) { struct stat bodyst; @@ -978,6 +1008,9 @@ int aret = aborted(req, _("Could not send request"), ret); return RETRY_RET(retry, ret, aret); } + + /* Return with request in progress if sending incrementally chunked body. */ + if (req->chunked) return ret; if (!req->use_expect100 && req->body_size > 0) { /* Send request body, if not using 100-continue. */ @@ -1154,6 +1187,50 @@ } } +int ne_finish_request(ne_request *req) +{ + struct body_reader *rdr; + const ne_status *const st = &req->status; + + /* Determine whether server claims HTTP/1.1 compliance. */ + req->session->is_http11 = (st->major_version == 1 && + st->minor_version > 0) || st->major_version > 1; + + /* Persistent connections supported implicitly in HTTP/1.1 */ + if (req->session->is_http11) req->can_persist = 1; + + ne_set_error(req->session, "%d %s", st->code, st->reason_phrase); + + /* Read the headers */ + HTTP_ERR(read_response_headers(req)); + +#ifdef NEON_SSL + /* Special case for CONNECT handling: the response has no body, + * and the connection can persist. */ + if (req->session->in_connect && st->klass == 2) { + req->resp.mode = R_NO_BODY; + req->can_persist = 1; + } +#endif + + /* HEAD requests and 201, 204, 205, 304 responses have no response body, + * regardless of what headers are present. */ + if (req->method_is_head || st->code == 201 || st->code == 204 || st->code == 205 || st->code == 304) + req->resp.mode = R_NO_BODY; + + /* Prepare for reading the response entity-body. Call each of the + * body readers and ask them whether they want to accept this + * response or not. */ + for (rdr = req->body_readers; rdr != NULL; rdr=rdr->next) { + rdr->use = rdr->accept_response(rdr->userdata, req, st); + } + + req->resp.left = req->resp.length; + req->resp.chunk_left = 0; + + return NE_OK; +} + int ne_begin_request(ne_request *req) { struct body_reader *rdr; @@ -1185,43 +1262,13 @@ ne_buffer_destroy(data); if (ret != NE_OK) return ret; - /* Determine whether server claims HTTP/1.1 compliance. */ - req->session->is_http11 = (st->major_version == 1 && - st->minor_version > 0) || st->major_version > 1; - - /* Persistent connections supported implicitly in HTTP/1.1 */ - if (req->session->is_http11) req->can_persist = 1; - - ne_set_error(req->session, "%d %s", st->code, st->reason_phrase); + /* Return with request in progress if sending incrementally chunked body. */ + if (req->chunked) + return ret; /* XXX perhaps NE_INPROGRESS? */ - /* Read the headers */ - HTTP_ERR(read_response_headers(req)); + ret = ne_finish_request(req); -#ifdef NEON_SSL - /* Special case for CONNECT handling: the response has no body, - * and the connection can persist. */ - if (req->session->in_connect && st->klass == 2) { - req->resp.mode = R_NO_BODY; - req->can_persist = 1; - } -#endif - - /* HEAD requests and 204, 205, 304 responses have no response body, - * regardless of what headers are present. */ - if (req->method_is_head || st->code==204 || st->code==205 || st->code==304) - req->resp.mode = R_NO_BODY; - - /* Prepare for reading the response entity-body. Call each of the - * body readers and ask them whether they want to accept this - * response or not. */ - for (rdr = req->body_readers; rdr != NULL; rdr=rdr->next) { - rdr->use = rdr->accept_response(rdr->userdata, req, st); - } - - req->resp.left = req->resp.length; - req->resp.chunk_left = 0; - - return NE_OK; + return ret; } int ne_end_request(ne_request *req) --- neon-0.24.7/src/ne_request.h.ark 2004-12-27 14:26:39.000000000 +0100 +++ neon-0.24.7/src/ne_request.h 2004-12-27 14:28:44.000000000 +0100 @@ -57,6 +57,18 @@ void ne_set_request_body_buffer(ne_request *req, const char *buffer, size_t size); +/* Mark the request body as incrementally chunked. */ +void ne_set_request_chunked(ne_request *req, int chunked) /*@modifies req @*/; + +/* Send request body chunk. + * Return 0 on success, else NE_* return. */ +int ne_send_request_chunk(ne_request *req, const char *buffer, size_t size) /*@modifies req @*/; + +/* Finish incrementally chunked request. */ +int ne_finish_request(ne_request *req) + /*@globals internalState @*/ + /*@modifies req, internalState @*/; + /* Send the contents of a file as the request body; 'fd' must be a * file descriptor of an open, seekable file. Current file offset of * fd is not retained (and ignored: the file is read from the the