summaryrefslogtreecommitdiff
path: root/src/ne_basic.c
diff options
context:
space:
mode:
authorjoe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845>2004-12-30 11:55:13 +0000
committerjoe <joe@61a7d7f5-40b7-0310-9c16-bb0ea8cb1845>2004-12-30 11:55:13 +0000
commit4bbd032fc525b0185c4bfe3f73395ab857e507e8 (patch)
tree9b0191b7f4e0b47888322184f0f9e4608d400ee2 /src/ne_basic.c
parent5313dc13b9ed83dc429edc0fcec68980254ac91b (diff)
downloadneon-4bbd032fc525b0185c4bfe3f73395ab857e507e8.tar.gz
Remove callback-based response header handling in favour of
ne_get_response_header interface: * src/ne_request.h (ne_get_response_header): New function, replacing ne_add_response_header_handler and ne_add_response_header_catcher. * src/ne_request.c (struct header_handler): Remove. (struct field): Add. (struct ne_request_s): Store a hash of header fields rather than a hash of callbacks. (te_hdr_handler, connection_hdr_handler, clength_hdr_handler, ne_add_response_header_catcher, ne_add_response_header_handler, ne_duplicate_header, ne_handle_numeric_header): Remove functions. (get_response_header_hv, ne_get_response_header, add_response_header, remove_response_header): New functions. (ne_request_create): Don't register the callbacks. (read_response_headers): Call add_response_header for each field. (ne_begin_request): Move handling of Connection, T-E and C-L headers here. Comply with 2616/14.10 w.r.t. Connection header handling in HTTP/1.0 responses. (ne_request_dispatch): Use ne_discard_response (unrelated). * src/ne_redirect.c (struct redirect): Remove location field. (post_send): Adjust to retrieve location header here. * src/ne_basic.h (ne_get_content_type): Replaces ne_content_type_handler. * src/ne_basic.c (dispatch_to_fd): New function. (get_to_fd, get_lastmodified, clength_hdr_handler, accept_206, content_range_hdr_handler): Remove functions. (ne_getmodtime): Adjust to use ne_get_response_header. (ne_get_range, ne_get, ne_post): Adjust to use dispatch_to_fd. (ne_get_content_type): Adjust for new API, use ne_get_response_header. (parse_dav_header, ne_options): Adjust to use ne_get_response_header. * src/ne_compress.c (struct ne_decompress_s): Add ne_request * field, remove enchdr field. (gz_reader): Retrieve C-E header on demand, here. (ne_decompress_reader, ne_decompress_destroy): Remove C-E response header duplication. * src/ne_auth.c (auth_request): Remove auth_hdr, auth_info_hdr fields. (ah_collect_header): Remove function. (ah_create, ah_destroy): Remove response-header callback handling. (ah_post_send): Retrieve -Authenticate header here; correctly handle the broken proxy which sends a 401 in response to CONNECT. * src/ne_locks.c (lk_startelm): Retrieve Lock-Token header here. (get_ltoken_hdr): Remove function. (ne_lock, ne_lock_refresh): Remove response-header handling. * test/basic.c (content_type): Test new interface. * test/request.c (expect_header_value): Adjust to accept NULL value, use ne_get_response_header interface. (multi_header): Test new ne_get_response_header multi-header handling. (multi_header2, strip_http10_connhdr, strip_http10_connhdr2): New tests. git-svn-id: http://svn.webdav.org/repos/projects/neon/trunk@367 61a7d7f5-40b7-0310-9c16-bb0ea8cb1845
Diffstat (limited to 'src/ne_basic.c')
-rw-r--r--src/ne_basic.c226
1 files changed, 66 insertions, 160 deletions
diff --git a/src/ne_basic.c b/src/ne_basic.c
index 0038778..f9cc348 100644
--- a/src/ne_basic.c
+++ b/src/ne_basic.c
@@ -50,27 +50,21 @@
#include "ne_dates.h"
#include "ne_i18n.h"
-/* Header parser to retrieve Last-Modified date */
-static void get_lastmodified(void *userdata, const char *value) {
- time_t *modtime = userdata;
- *modtime = ne_httpdate_parse(value);
-}
-
int ne_getmodtime(ne_session *sess, const char *uri, time_t *modtime)
{
ne_request *req = ne_request_create(sess, "HEAD", uri);
+ const char *value;
int ret;
- ne_add_response_header_handler(req, "Last-Modified", get_lastmodified,
- modtime);
-
- *modtime = -1;
-
ret = ne_request_dispatch(req);
+ value = ne_get_response_header(req, "Last-Modified");
+
if (ret == NE_OK && ne_get_status(req)->klass != 2) {
*modtime = -1;
ret = NE_ERROR;
+ } else if (value) {
+ *modtime = ne_httpdate_parse(value);
}
ne_request_destroy(req);
@@ -113,126 +107,70 @@ int ne_put(ne_session *sess, const char *uri, int fd)
return ret;
}
-struct get_context {
- int error;
- ne_session *session;
- off_t total;
- int fd; /* used in get_to_fd */
- ne_content_range *range;
-};
-
-static int get_to_fd(void *userdata, const char *block, size_t length)
+/* Dispatch a GET request REQ, writing the response body to FD fd. If
+ * RANGE is non-NULL, then it is the value of the Range request
+ * header, e.g. "bytes=1-5". Returns an NE_* error code. */
+static int dispatch_to_fd(ne_request *req, int fd, const char *range)
{
- struct get_context *ctx = userdata;
- ssize_t ret;
-
- if (ctx->error) {
- return -1;
- }
-
- if (!ctx->error) {
- while (length > 0) {
- ret = write(ctx->fd, block, length);
- if (ret < 0) {
- char err[200];
- ne_strerror(errno, err, sizeof err);
- ne_set_error(ctx->session, _("Could not write to file: %s"),
- err);
- return -1;
- } else {
- length -= ret;
- block += ret;
- }
- }
- }
-
- return 0;
-}
-
-static int accept_206(void *ud, ne_request *req, const ne_status *st)
-{
- return (st->code == 206);
-}
-
-static void clength_hdr_handler(void *ud, const char *value)
-{
- struct get_context *ctx = ud;
- off_t len = strtol(value, NULL, 10);
-
- if (ctx->range->end == -1) {
- ctx->range->end = ctx->range->start + len - 1;
- ctx->range->total = len;
- }
- else if (len != ctx->total) {
- NE_DEBUG(NE_DBG_HTTP,
- "Expecting %" NE_FMT_OFF_T " bytes, "
- "got entity of length %" NE_FMT_OFF_T "\n",
- ctx->total, len);
- ne_set_error(ctx->session, _("Response not of expected length"));
- ctx->error = 1;
- }
-}
-
-static void content_range_hdr_handler(void *ud, const char *value)
-{
- struct get_context *ctx = ud;
+ ne_session *const sess = ne_get_session(req);
+ const ne_status *const st = ne_get_status(req);
+ int ret;
- if (strncmp(value, "bytes ", 6) != 0) {
- ne_set_error(ctx->session, ("Response range using unrecognized unit"));
- ctx->error = 1;
- }
+ do {
+ const char *value;
+
+ ret = ne_begin_request(req);
+ if (ret != NE_OK) break;
+
+ value = ne_get_response_header(req, "Content-Range");
+
+ /* For a 206 response, check that a Content-Range header is
+ * given which matches the Range request header. */
+ if (range && st->code == 206
+ && (value == NULL || strncmp(value, "bytes ", 6) != 0
+ || strcmp(range + 6, value + 6))) {
+ ne_set_error(sess, _("Response did not include requested range"));
+ return NE_ERROR;
+ }
+
+ if ((range && st->code == 206) || (!range && st->klass == 2)) {
+ ret = ne_read_response_to_fd(req, fd);
+ } else {
+ ret = ne_discard_response(req);
+ }
+
+ if (ret == NE_OK) ret = ne_end_request(req);
+ } while (ret == NE_RETRY);
- /* TODO: verify against requested range. */
+ return ret;
}
int ne_get_range(ne_session *sess, const char *uri,
ne_content_range *range, int fd)
{
ne_request *req = ne_request_create(sess, "GET", uri);
- struct get_context ctx;
const ne_status *status;
int ret;
+ char brange[64];
if (range->end == -1) {
- ctx.total = -1;
- }
- else {
- ctx.total = (range->end - range->start) + 1;
- }
-
- NE_DEBUG(NE_DBG_HTTP, "Range total: %" NE_FMT_OFF_T "\n", ctx.total);
-
- ctx.fd = fd;
- ctx.error = 0;
- ctx.range = range;
- ctx.session = sess;
-
- ne_add_response_header_handler(req, "Content-Length",
- clength_hdr_handler, &ctx);
- ne_add_response_header_handler(req, "Content-Range",
- content_range_hdr_handler,
- &ctx);
-
- ne_add_response_body_reader(req, accept_206, get_to_fd, &ctx);
-
- if (range->end == -1) {
- ne_print_request_header(req, "Range", "bytes=%" NE_FMT_OFF_T "-",
- range->start);
+ ne_snprintf(brange, sizeof brange, "bytes=%" NE_FMT_OFF_T "-",
+ range->start);
}
else {
- ne_print_request_header(req, "Range",
- "bytes=%" NE_FMT_OFF_T "-%" NE_FMT_OFF_T,
- range->start, range->end);
+ ne_snprintf(brange, sizeof brange,
+ "bytes=%" NE_FMT_OFF_T "-%" NE_FMT_OFF_T,
+ range->start, range->end);
}
+
+ ne_add_request_header(req, "Range", brange);
ne_add_request_header(req, "Accept-Ranges", "bytes");
- ret = ne_request_dispatch(req);
+ ret = dispatch_to_fd(req, fd, brange);
status = ne_get_status(req);
- if (ctx.error) {
- ret = NE_ERROR;
- } else if (status && status->code == 416) {
+ if (ret == NE_OK && status->code == 416) {
/* connection is terminated too early with Apache/1.3, so we check
* this even if ret == NE_ERROR... */
ne_set_error(sess, _("Range is not satisfiable"));
@@ -258,26 +196,11 @@ int ne_get_range(ne_session *sess, const char *uri,
int ne_get(ne_session *sess, const char *uri, int fd)
{
ne_request *req = ne_request_create(sess, "GET", uri);
- struct get_context ctx;
int ret;
- ctx.total = -1;
- ctx.fd = fd;
- ctx.error = 0;
- ctx.session = sess;
-
- /* Read the value of the Content-Length header into ctx.total */
- ne_add_response_header_handler(req, "Content-Length",
- ne_handle_numeric_header,
- &ctx.total);
-
- ne_add_response_body_reader(req, ne_accept_2xx, get_to_fd, &ctx);
-
- ret = ne_request_dispatch(req);
+ ret = dispatch_to_fd(req, fd, NULL);
- if (ctx.error) {
- ret = NE_ERROR;
- } else if (ret == NE_OK && ne_get_status(req)->klass != 2) {
+ if (ret == NE_OK && ne_get_status(req)->klass != 2) {
ret = NE_ERROR;
}
@@ -291,28 +214,13 @@ int ne_get(ne_session *sess, const char *uri, int fd)
int ne_post(ne_session *sess, const char *uri, int fd, const char *buffer)
{
ne_request *req = ne_request_create(sess, "POST", uri);
- struct get_context ctx;
int ret;
- ctx.total = -1;
- ctx.fd = fd;
- ctx.error = 0;
- ctx.session = sess;
-
- /* Read the value of the Content-Length header into ctx.total */
- ne_add_response_header_handler(req, "Content-Length",
- ne_handle_numeric_header, &ctx.total);
-
- ne_add_response_body_reader(req, ne_accept_2xx, get_to_fd, &ctx);
-
ne_set_request_body_buffer(req, buffer, strlen(buffer));
- ret = ne_request_dispatch(req);
+ ret = dispatch_to_fd(req, fd, NULL);
- if (ctx.error) {
- ret = NE_ERROR;
- }
- else if (ret == NE_OK && ne_get_status(req)->klass != 2) {
+ if (ret == NE_OK && ne_get_status(req)->klass != 2) {
ret = NE_ERROR;
}
@@ -321,18 +229,19 @@ int ne_post(ne_session *sess, const char *uri, int fd, const char *buffer)
return ret;
}
-void ne_content_type_handler(void *userdata, const char *value)
+int ne_get_content_type(ne_request *req, ne_content_type *ct)
{
- ne_content_type *ct = userdata;
+ const char *value;
char *sep, *stype;
+ value = ne_get_response_header(req, "Content-Type");
+ if (value == NULL || strchr(value, '/') == NULL) {
+ return -1;
+ }
+
ct->value = ne_strdup(value);
stype = strchr(ct->value, '/');
- if (!stype) {
- NE_FREE(ct->value);
- return;
- }
*stype++ = '\0';
ct->type = ct->value;
@@ -367,12 +276,13 @@ void ne_content_type_handler(void *userdata, const char *value)
else
ct->charset = "ISO-8859-1";
}
+
+ return 0;
}
-static void dav_hdr_handler(void *userdata, const char *value)
+static void parse_dav_header(const char *value, ne_server_capabilities *caps)
{
char *tokens = ne_strdup(value), *pnt = tokens;
- ne_server_capabilities *caps = userdata;
do {
char *tok = ne_qtoken(&pnt, ',', "\"'");
@@ -390,19 +300,15 @@ static void dav_hdr_handler(void *userdata, const char *value)
} while (pnt != NULL);
ne_free(tokens);
-
}
-int ne_options(ne_session *sess, const char *uri,
- ne_server_capabilities *caps)
+int ne_options(ne_session *sess, const char *uri, ne_server_capabilities *caps)
{
ne_request *req = ne_request_create(sess, "OPTIONS", uri);
+ int ret = ne_request_dispatch(req);
+ const char *header = ne_get_response_header(req, "DAV");
- int ret;
-
- ne_add_response_header_handler(req, "DAV", dav_hdr_handler, caps);
-
- ret = ne_request_dispatch(req);
+ if (header) parse_dav_header(header, caps);
if (ret == NE_OK && ne_get_status(req)->klass != 2) {
ret = NE_ERROR;