From 0e2b44af619e46e365971ea52b97457bc0778cd3 Mon Sep 17 00:00:00 2001 From: Christopher Davis <chrisd@mangrin.org> Date: Mon, 11 Jan 2010 18:55:41 -0800 Subject: [PATCH] Try to read POST requests to local configuration interface correctly. --- client.c | 1 - local.c | 113 +++++++++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 76 insertions(+), 38 deletions(-) diff --git a/client.c b/client.c index 18f1d72..2404c81 100644 --- a/client.c +++ b/client.c @@ -987,7 +987,6 @@ httpClientDiscardBody(HTTPConnectionPtr connection) connection->reqlen = 0; httpConnectionDestroyReqbuf(connection); } - connection->reqte = TE_UNKNOWN; if(connection->bodylen > 0) { httpSetTimeout(connection, clientTimeout); diff --git a/local.c b/local.c index 82106c4..f59ab63 100644 --- a/local.c +++ b/local.c @@ -67,8 +67,8 @@ httpLocalRequest(ObjectPtr object, int method, int from, int to, requestor, closure); if(method >= METHOD_POST) { + httpClientDiscardBody(requestor->connection); httpClientError(requestor, 405, internAtom("Method not allowed")); - requestor->connection->flags &= ~CONN_READER; return 1; } @@ -295,11 +295,47 @@ httpSpecialRequest(ObjectPtr object, int method, int from, int to, return 1; } +#define MAXBODY(c) (((c)->flags & CONN_BIGREQBUF)? bigBufferSize : CHUNK_SIZE) + +static void +writeContinue(HTTPConnectionPtr client) +{ + static char httpContinue[] = "HTTP/1.1 100 Continue\r\n\r\n"; + + /* don't bother writing continue if the post is already completed */ + if (client->reqlen - client->reqbegin < client->bodylen) { + do_stream(IO_WRITE, client->fd, 0, httpContinue, 25, + httpErrorNofinishStreamHandler, client); + } +} + +static int +validateRequest(HTTPConnectionPtr client) +{ + ObjectPtr object = client->request->object; + + if (disableConfiguration) { + abortObject(object, 403, internAtom("Action not allowed")); + } else if (client->bodylen > MAXBODY(client)) { + abortObject(object, 411, internAtom("POST too large")); + } else if (!matchUrl("/polipo/status", object) && + !matchUrl("/polipo/config", object)) { + abortObject(object, 404, internAtom("Not found")); + } else + return 0; + + httpClientDiscardBody(client); + notifyObject(object); + + return -1; +} + int httpSpecialSideRequest(ObjectPtr object, int method, int from, int to, HTTPRequestPtr requestor, void *closure) { HTTPConnectionPtr client = requestor->connection; + int waiting = 0; assert(client->request == requestor); @@ -309,13 +345,24 @@ httpSpecialSideRequest(ObjectPtr object, int method, int from, int to, return 1; } + if (requestor->flags & REQUEST_WAIT_CONTINUE) { + requestor->flags &= ~REQUEST_WAIT_CONTINUE; + waiting = 1; + } + + if (validateRequest(client) < 0) + return 1; + + if (waiting) + writeContinue(client); + return httpSpecialDoSide(requestor); } -int -httpSpecialDoSide(HTTPRequestPtr requestor) +static int +readFinished(HTTPConnectionPtr client) { - HTTPConnectionPtr client = requestor->connection; + HTTPRequestPtr request = client->request; if(client->reqlen - client->reqbegin >= client->bodylen) { AtomPtr data; @@ -325,19 +372,25 @@ httpSpecialDoSide(HTTPRequestPtr requestor) client->reqlen = 0; if(data == NULL) { do_log(L_ERROR, "Couldn't allocate data.\n"); - httpClientError(requestor, 500, + httpClientError(request, 500, internAtom("Couldn't allocate data")); return 1; } - httpSpecialDoSideFinish(data, requestor); + httpSpecialDoSideFinish(data, request); return 1; } - if(client->reqlen - client->reqbegin >= CHUNK_SIZE) { - httpClientError(requestor, 500, internAtom("POST too large")); - return 1; - } + return 0; +} +int +httpSpecialDoSide(HTTPRequestPtr requestor) +{ + HTTPConnectionPtr client = requestor->connection; + + if (readFinished(client)) + return 1; + if(client->reqbegin > 0 && client->reqlen > client->reqbegin) { memmove(client->reqbuf, client->reqbuf + client->reqbegin, client->reqlen - client->reqbegin); @@ -346,7 +399,7 @@ httpSpecialDoSide(HTTPRequestPtr requestor) client->reqbegin = 0; do_stream(IO_READ | IO_NOTNOW, client->fd, - client->reqlen, client->reqbuf, CHUNK_SIZE, + client->reqlen, client->reqbuf, MAXBODY(client), httpSpecialClientSideHandler, client); return 1; } @@ -358,36 +411,22 @@ httpSpecialClientSideHandler(int status, { HTTPConnectionPtr connection = srequest->data; HTTPRequestPtr request = connection->request; - int push; - if((request->object->flags & OBJECT_ABORTED) || - !(request->object->flags & OBJECT_INPROGRESS)) { - httpClientDiscardBody(connection); - httpClientError(request, 503, internAtom("Post aborted")); - return 1; - } - - if(status < 0) { - do_log_error(L_ERROR, -status, "Reading from client"); - if(status == -EDOGRACEFUL) - httpClientFinish(connection, 1); - else - httpClientFinish(connection, 2); + if(status) { + connection->flags &= ~CONN_READER; + if (request->chandler) { + unregisterConditionHandler(request->chandler); + request->chandler = NULL; + } + do_log(L_ERROR, "Incomplete client request.\n"); + httpClientRawError(connection, 502, + internAtom("Incomplete client request"), 1); return 1; } - push = MIN(srequest->offset - connection->reqlen, - connection->bodylen - connection->reqoffset); - if(push > 0) { - connection->reqlen += push; - httpSpecialDoSide(request); - } + connection->reqlen = srequest->offset; - do_log(L_ERROR, "Incomplete client request.\n"); - connection->flags &= ~CONN_READER; - httpClientRawError(connection, 502, - internAtom("Incomplete client request"), 1); - return 1; + return readFinished(connection); } int @@ -480,7 +519,7 @@ httpSpecialDoSideFinish(AtomPtr data, HTTPRequestPtr requestor) object->flags &= ~OBJECT_INITIAL; object->length = 0; } else { - abortObject(object, 405, internAtom("Method not allowed")); + abortObject(object, 404, internAtom("Not found")); } out: -- 1.7.2.5