diff options
Diffstat (limited to 'NetEx/HttpServer.cpp')
-rw-r--r-- | NetEx/HttpServer.cpp | 1027 |
1 files changed, 1027 insertions, 0 deletions
diff --git a/NetEx/HttpServer.cpp b/NetEx/HttpServer.cpp new file mode 100644 index 0000000..92a13b2 --- /dev/null +++ b/NetEx/HttpServer.cpp @@ -0,0 +1,1027 @@ +/* Starshatter OpenSource Distribution + Copyright (c) 1997-2004, Destroyer Studios LLC. + All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name "Destroyer Studios" nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + SUBSYSTEM: NetEx.lib + FILE: HttpServer.cpp + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + Network Server Pump for HTTP Server +*/ + + +#include "MemDebug.h" +#include "HttpServer.h" +#include "NetLayer.h" + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> + +// +-------------------------------------------------------------------+ + +HttpServer::HttpServer(WORD port, int poolsize) + : NetServer(port, poolsize) +{ + http_server_name = "Generic HttpServer 1.0"; +} + +HttpServer::~HttpServer() +{ } + +// +--------------------------------------------------------------------+ + +Text +HttpServer::ProcessRequest(Text msg, const NetAddr& addr) +{ + HttpRequest request(msg); + HttpResponse response; + + request.SetClientAddr(addr); + + switch (request.Method()) { + case HttpRequest::HTTP_GET: + if (DoGet(request, response)) + return response; + + case HttpRequest::HTTP_POST: + if (DoPost(request, response)) + return response; + + case HttpRequest::HTTP_HEAD: + if (DoHead(request, response)) + return response; + } + + return ErrorResponse(); +} + +// +--------------------------------------------------------------------+ + +Text +HttpServer::GetServerName() +{ + return http_server_name; +} + +void +HttpServer::SetServerName(const char* name) +{ + http_server_name = name; +} + +// +--------------------------------------------------------------------+ + +Text +HttpServer::DefaultResponse() +{ + Text response = "HTTP/1.1 200 OK\nServer: "; + response += http_server_name; + response += "\nMIME-Version: 1.0\nContent-Type: text/html\nConnection: close\n\n"; + + return response; +} + +Text +HttpServer::ErrorResponse() +{ + Text response = "HTTP/1.1 500 Internal Server Error\nServer:"; + response += http_server_name; + response += "\nMIME-Version: 1.0\nContent-Type: text/html\nConnection: close\n\n"; + + response += "<html><head><title>"; + response += http_server_name; + response += " Error</title></head>\n"; + response += "<body bgcolor=\"black\" text=\"white\">\n<h1>"; + response += http_server_name; + response += "</h1>\n<p>Veruca... sweetheart... angel... I'm not a magician!\n"; + response += "</body></html>\n\n"; + + return response; +} + +// +--------------------------------------------------------------------+ + +bool +HttpServer::DoGet(HttpRequest& request, HttpResponse& response) +{ + char buffer[1024]; + Text content; + + content = "<html><head><title>"; + content += http_server_name; + content += "</title></head>\n"; + content += "<body bgcolor=\"white\" text=\"black\">\n<h1>"; + content += http_server_name; + content += "</h1>\n"; + content += "<br><h3>Client Address:</h3><p>\n"; + + sprintf_s(buffer, "%d.%d.%d.%d:%d<br><br>\n", + client_addr.B1(), + client_addr.B2(), + client_addr.B3(), + client_addr.B4(), + client_addr.Port()); + + content += buffer; + content += "<h3>Request Method:</h3><p>\n"; + + switch (request.Method()) { + case HttpRequest::HTTP_GET: + content += "GET"; + break; + + case HttpRequest::HTTP_POST: + content += "POST"; + break; + + case HttpRequest::HTTP_HEAD: + content += "HEAD"; + break; + + default: + content += "(unsupported?)"; + break; + } + + content += "<br>\n"; + content += "<br><h3>URI Requested:</h3><p>\n"; + content += request.URI(); + content += "<br>\n"; + + if (request.GetQuery().size() > 0) { + content += "<br><h3>Query Parameters:</h3>\n"; + + ListIter<HttpParam> q_iter = request.GetQuery(); + while (++q_iter) { + HttpParam* q = q_iter.value(); + sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", q->name.data(), q->value.data()); + content += buffer; + } + } + + content += "<br><h3>Request Headers:</h3>\n"; + ListIter<HttpParam> h_iter = request.GetHeaders(); + while (++h_iter) { + HttpParam* h = h_iter.value(); + sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", h->name.data(), h->value.data()); + content += buffer; + } + + content += "</body></html>\n\n"; + + response.SetStatus(HttpResponse::SC_OK); + response.AddHeader("Server", http_server_name); + response.AddHeader("MIME-Version", "1.0"); + response.AddHeader("Content-Type", "text/html"); + response.SetContent(content); + + return true; +} + +// +--------------------------------------------------------------------+ + +bool +HttpServer::DoPost(HttpRequest& request, HttpResponse& response) +{ + return DoGet(request, response); +} + +// +--------------------------------------------------------------------+ + +bool +HttpServer::DoHead(HttpRequest& request, HttpResponse& response) +{ + if (DoGet(request, response)) { + int len = response.Content().length(); + + char buffer[256]; + sprintf_s(buffer, "%d", len); + response.SetHeader("Content-Length", buffer); + response.SetContent(""); + + return true; + } + + return false; +} + +// +--------------------------------------------------------------------+ +// +--------------------------------------------------------------------+ +// +--------------------------------------------------------------------+ + +HttpRequest::HttpRequest(const char* r) + : method(0) +{ + if (r && *r) + ParseRequest(r); +} + +HttpRequest::~HttpRequest() +{ + query.destroy(); + headers.destroy(); + cookies.destroy(); +} + +// +--------------------------------------------------------------------+ + +void +HttpRequest::ParseRequest(Text request) +{ + if (request.length() <= 8) + return; + + const char* pReq = 0; + const char* pURI = 0; + const char* pQuery = 0; + + switch (request[0]) { + case 'G': + if (request.indexOf("GET") == 0) + method = HTTP_GET; + break; + + case 'P': + if (request.indexOf("POST") == 0) + method = HTTP_POST; + break; + + case 'H': + if (request.indexOf("HEAD") == 0) + method = HTTP_HEAD; + break; + + default: + break; + } + + if (!method) return; + + char buffer[1024]; + int i = 0; + + // save the request line: + pReq = request.data(); + while (*pReq && *pReq != '\n') + buffer[i++] = *pReq++; + buffer[i] = 0; + + request_line = buffer; + i = 0; + + // find the URI: + pURI = request.data(); + while (*pURI && !isspace(*pURI)) + pURI++; + + while (*pURI && isspace(*pURI)) + pURI++; + + // copy the URI and find the query string: + while (*pURI && *pURI != '?' && !isspace(*pURI)) { + buffer[i++] = *pURI++; + } + + buffer[i] = 0; + uri = buffer; + pQuery = pURI; + + // parse the query string: + if (*pQuery == '?') { + pQuery++; + + while (*pQuery && !isspace(*pQuery)) { + char name_buf[1024]; + char value_buf[1024]; + + i = 0; + while (*pQuery && *pQuery != '=' && !isspace(*pQuery)) + name_buf[i++] = *pQuery++; + name_buf[i] = 0; + + if (*pQuery == '=') + pQuery++; + + i = 0; + while (*pQuery && *pQuery != '&' && !isspace(*pQuery)) + value_buf[i++] = *pQuery++; + value_buf[i] = 0; + + if (*pQuery == '&') + pQuery++; + + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, DecodeParam(value_buf)); + if (param) + query.append(param); + } + } + + // get the headers: + const char* p = request.data(); + while (*p && *p != '\n') + p++; + + if (*p == '\n') p++; + + while (*p && *p != '\r' && *p != '\n') { + char name_buf[1024]; + char value_buf[1024]; + + i = 0; + while (*p && *p != ':') + name_buf[i++] = *p++; + name_buf[i] = 0; + + p++; // skip ':' + while (isspace(*p)) p++; // skip spaces + + i = 0; + while (*p && *p != '\r' && *p != '\n') // read to end of header line + value_buf[i++] = *p++; + value_buf[i] = 0; + + if (!_stricmp(name_buf, "Cookie")) { + ParseCookie(value_buf); + } + else { + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, value_buf); + if (param) + headers.append(param); + } + + while (*p && *p != '\n') + p++; + + if (*p == '\n') p++; + } + + if (method == HTTP_POST && *p) { + while (*p == '\n' || *p == '\r') + p++; + + content = *p; + pQuery = p; + + while (*pQuery && !isspace(*pQuery)) { + char name_buf[1024]; + char value_buf[1024]; + + i = 0; + while (*pQuery && *pQuery != '=' && !isspace(*pQuery)) + name_buf[i++] = *pQuery++; + name_buf[i] = 0; + + if (*pQuery == '=') + pQuery++; + + i = 0; + while (*pQuery && *pQuery != '&' && !isspace(*pQuery)) + value_buf[i++] = *pQuery++; + value_buf[i] = 0; + + if (*pQuery == '&') + pQuery++; + + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, DecodeParam(value_buf)); + if (param) + query.append(param); + } + } +} + +void +HttpRequest::ParseCookie(const char* param) +{ + const char* p = param; + + while (p && *p) { + while (isspace(*p)) p++; + + // just ignore reserved attributes + if (*p == '$') { + while (*p && !isspace(*p) && *p != ';') p++; + + if (*p == ';') + p++; + } + + // found a cookie! + else if (isalpha(*p)) { + char name[1024]; + char data[1024]; + + char* d = name; + while (*p && *p != '=') + *d++ = *p++; + *d = 0; + + if (*p == '=') + p++; + + if (*p == '"') + p++; + + d = data; + while (*p && *p != '"' && *p != ';') + *d++ = *p++; + *d = 0; + + if (*p == '"') + p++; + + if (*p == ';') + p++; + + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, data); + if (param) + cookies.append(param); + } + + // this shouldn't happen - abandon the parse + else { + return; + } + } +} + +// +--------------------------------------------------------------------+ + +Text +HttpRequest::GetParam(const char* name) +{ + ListIter<HttpParam> iter = query; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) + return p->value; + } + + return Text(); +} + +// +--------------------------------------------------------------------+ + +Text +HttpRequest::GetHeader(const char* name) +{ + ListIter<HttpParam> iter = headers; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) + return p->value; + } + + return Text(); +} + +void +HttpRequest::SetHeader(const char* name, const char* value) +{ + ListIter<HttpParam> iter = headers; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) { + p->value = value; + return; + } + } + + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value); + if (param) + headers.append(param); +} + +void +HttpRequest::AddHeader(const char* name, const char* value) +{ + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value); + if (param) + headers.append(param); +} + +// +--------------------------------------------------------------------+ + +Text +HttpRequest::GetCookie(const char* name) +{ + ListIter<HttpParam> iter = cookies; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) + return p->value; + } + + return Text(); +} + +void +HttpRequest::SetCookie(const char* name, const char* value) +{ + ListIter<HttpParam> iter = cookies; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) { + p->value = value; + return; + } + } + + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value); + if (param) + cookies.append(param); +} + +void +HttpRequest::AddCookie(const char* name, const char* value) +{ + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value); + if (param) + cookies.append(param); +} + +// +--------------------------------------------------------------------+ + +Text +HttpRequest::DecodeParam(const char* value) +{ + if (!value || !*value) return ""; + + int size = strlen(value); + char val = 0; + char code[4]; + char sbuf[256]; + char* lbuf = 0; + + char* dst = sbuf; + char* p = sbuf; + + if (size > 255) { + lbuf = new(__FILE__,__LINE__) char[size+1]; + dst = lbuf; + p = lbuf; + } + + if (p) { + while (*value) { + switch (*value) { + default: *p++ = *value; break; + case '+': *p++ = ' '; break; + + case '%': + value++; + code[0] = *value++; + code[1] = *value; + code[2] = 0; + + val = (char) strtol(code, 0, 16); + *p++ = val; + break; + } + + value++; + } + + *p = 0; + } + + Text result = dst; + + if (lbuf) + delete [] lbuf; + + return result; +} + +// +--------------------------------------------------------------------+ + +Text +HttpRequest::EncodeParam(const char* value) +{ + if (!value || !*value) return ""; + + int size = strlen(value); + char hex1 = 0; + char hex2 = 0; + + char sbuf[1024]; + char* lbuf = 0; + + char* dst = sbuf; + char* p = sbuf; + + if (size > 255) { + lbuf = new(__FILE__,__LINE__) char[4*size+1]; + dst = lbuf; + p = lbuf; + } + + if (p) { + while (*value) { + switch (*value) { + default: *p++ = *value; break; + case ' ': *p++ = '+'; break; + + case '?': *p++ = '%'; *p++ = '3'; *p++ = 'F'; break; + case '&': *p++ = '%'; *p++ = '2'; *p++ = '6'; break; + case ':': *p++ = '%'; *p++ = '3'; *p++ = 'A'; break; + case '/': *p++ = '%'; *p++ = '2'; *p++ = 'F'; break; + case '\\': *p++ = '%'; *p++ = '5'; *p++ = 'C'; break; + case '%': *p++ = '%'; *p++ = '2'; *p++ = '5'; break; + case '|': *p++ = '%'; *p++ = '7'; *p++ = 'C'; break; + case '<': *p++ = '%'; *p++ = '3'; *p++ = 'C'; break; + case '>': *p++ = '%'; *p++ = '3'; *p++ = 'E'; break; + case '[': *p++ = '%'; *p++ = '5'; *p++ = 'B'; break; + case ']': *p++ = '%'; *p++ = '5'; *p++ = 'D'; break; + case '{': *p++ = '%'; *p++ = '7'; *p++ = 'B'; break; + case '}': *p++ = '%'; *p++ = '7'; *p++ = 'D'; break; + case '"': *p++ = '%'; *p++ = '2'; *p++ = '2'; break; + case '^': *p++ = '%'; *p++ = '5'; *p++ = 'E'; break; + case '`': *p++ = '%'; *p++ = '6'; *p++ = '0'; break; + case '\n': break; + case '\r': break; + case '\t': break; + } + + value++; + } + + *p = 0; + } + + Text result = dst; + + if (lbuf) + delete [] lbuf; + + return result; +} + +// +--------------------------------------------------------------------+ + +HttpRequest::operator Text() +{ + Text response = request_line.data(); + response += "\n"; + + for (int i = 0; i < headers.size(); i++) { + HttpParam* h = headers[i]; + response += h->name; + response += ": "; + response += h->value; + response += "\n"; + } + + for (int i = 0; i < cookies.size(); i++) { + HttpParam* c = cookies[i]; + response += "Cookie: "; + response += c->name; + response += "=\""; + response += c->value; + response += "\"\n"; + } + + response += "Connection: close\n\n"; + response += content; + + return response; +} + +// +--------------------------------------------------------------------+ +// +--------------------------------------------------------------------+ +// +--------------------------------------------------------------------+ + +HttpResponse::HttpResponse(int stat, const char* data) + : status(stat), content(data) +{ } + +HttpResponse::HttpResponse(const char* r) + : status(0), content(r) +{ + if (r && *r) + ParseResponse(r); +} + +HttpResponse::~HttpResponse() +{ + headers.destroy(); + cookies.destroy(); +} + +// +--------------------------------------------------------------------+ + +HttpResponse::operator Text() +{ + Text response; + + switch (status) { + case SC_CONTINUE : response = "HTTP/1.1 100 Continue\n"; break; + case SC_SWITCHING_PROTOCOLS : response = "HTTP/1.1 101 Switching Protocols\n"; break; + + case SC_OK : response = "HTTP/1.1 200 OK\n"; break; + case SC_CREATED : response = "HTTP/1.1 201 Created\n"; break; + case SC_ACCEPTED : response = "HTTP/1.1 202 Accepted\n"; break; + case SC_NON_AUTHORITATIVE : response = "HTTP/1.1 203 Non Authoritative\n"; break; + case SC_NO_CONTENT : response = "HTTP/1.1 204 No Content\n"; break; + case SC_RESET_CONTENT : response = "HTTP/1.1 205 Reset Content\n"; break; + case SC_PARTIAL_CONTENT : response = "HTTP/1.1 206 Partial Content\n"; break; + + case SC_MULTIPLE_CHOICES : response = "HTTP/1.1 300 Multiple Choices\n"; break; + case SC_MOVED_PERMANENTLY : response = "HTTP/1.1 301 Moved Permanently\n"; break; + case SC_FOUND : response = "HTTP/1.1 302 Found\n"; break; + case SC_SEE_OTHER : response = "HTTP/1.1 303 See Other\n"; break; + case SC_NOT_MODIFIED : response = "HTTP/1.1 304 Not Modified\n"; break; + case SC_USE_PROXY : response = "HTTP/1.1 305 Use Proxy\n"; break; + case SC_TEMPORARY_REDIRECT : response = "HTTP/1.1 307 Temporary Redirect\n"; break; + + case SC_BAD_REQUEST : response = "HTTP/1.1 400 Bad Request\n"; break; + case SC_UNAUTHORIZED : response = "HTTP/1.1 401 Unauthorized\n"; break; + case SC_PAYMENT_REQUIRED : response = "HTTP/1.1 402 Payment Required\n"; break; + case SC_FORBIDDEN : response = "HTTP/1.1 403 Forbidden\n"; break; + case SC_NOT_FOUND : response = "HTTP/1.1 404 Not Found\n"; break; + case SC_METHOD_NOT_ALLOWED : response = "HTTP/1.1 405 Method Not Allowed\n"; break; + case SC_NOT_ACCEPTABLE : response = "HTTP/1.1 406 Not Acceptable\n"; break; + case SC_PROXY_AUTH_REQ : response = "HTTP/1.1 407 Proxy Authorization Req\n"; break; + case SC_REQUEST_TIME_OUT : response = "HTTP/1.1 408 Request Timeout\n"; break; + case SC_CONFLICT : response = "HTTP/1.1 409 Conflict\n"; break; + case SC_GONE : response = "HTTP/1.1 410 Gone\n"; break; + case SC_LENGTH_REQUIRED : response = "HTTP/1.1 411 Length Required\n"; break; + + default: + case SC_SERVER_ERROR : response = "HTTP/1.1 500 Internal Server Error\n"; break; + case SC_NOT_IMPLEMENTED : response = "HTTP/1.1 501 Not Implemented\n"; break; + case SC_BAD_GATEWAY : response = "HTTP/1.1 502 Bad Gateway\n"; break; + case SC_SERVICE_UNAVAILABLE : response = "HTTP/1.1 503 Service Unavailable\n"; break; + case SC_GATEWAY_TIMEOUT : response = "HTTP/1.1 504 Gateway Timeout\n"; break; + case SC_VERSION_NOT_SUPPORTED: response = "HTTP/1.1 505 HTTP Version Not Supported\n"; break; + } + + SetHeader("Connection", "close"); + + char buffer[256]; + + if (content.length()) { + sprintf_s(buffer, "%d", content.length()); + SetHeader("Content-Length", buffer); + } + + for (int i = 0; i < cookies.size(); i++) { + HttpParam* cookie = cookies.at(i); + sprintf_s(buffer, "%s=\"%s\"; Version=\"1\"", cookie->name.data(), cookie->value.data()); + + AddHeader("Set-Cookie", buffer); + } + + for (int i = 0; i < headers.size(); i++) { + const HttpParam* p = headers.at(i); + sprintf_s(buffer, "%s: %s\n", p->name.data(), p->value.data()); + response += buffer; + } + + response += "\n"; + response += content; + + return response; +} + +// +--------------------------------------------------------------------+ + +Text +HttpResponse::GetHeader(const char* name) +{ + ListIter<HttpParam> iter = headers; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) + return p->value; + } + + return Text(); +} + +void +HttpResponse::SetHeader(const char* name, const char* value) +{ + ListIter<HttpParam> iter = headers; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) { + p->value = value; + return; + } + } + + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value); + if (param) + headers.append(param); +} + +void +HttpResponse::AddHeader(const char* name, const char* value) +{ + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value); + if (param) + headers.append(param); +} + +// +--------------------------------------------------------------------+ + +Text +HttpResponse::GetCookie(const char* name) +{ + ListIter<HttpParam> iter = cookies; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) + return p->value; + } + + return Text(); +} + +void +HttpResponse::SetCookie(const char* name, const char* value) +{ + ListIter<HttpParam> iter = cookies; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) { + p->value = value; + return; + } + } + + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value); + if (param) + cookies.append(param); +} + +void +HttpResponse::AddCookie(const char* name, const char* value) +{ + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value); + if (param) + cookies.append(param); +} + +// +--------------------------------------------------------------------+ + +void +HttpResponse::SendRedirect(const char* url) +{ + status = SC_TEMPORARY_REDIRECT; + SetHeader("Location", url); +} + +// +--------------------------------------------------------------------+ + +void +HttpResponse::ParseResponse(Text response) +{ + if (response.length() <= 12 || response.indexOf("HTTP/1.") != 0) + return; + + const char* pStatus = response.data() + 9; + + sscanf_s(pStatus, "%d", &status); + if (!status) return; + + int i = 0; + + // get the headers: + const char* p = response.data(); + while (*p && *p != '\n') + p++; + + if (*p == '\n') p++; + + while (*p && *p != '\r' && *p != '\n') { + char name_buf[1024]; + char value_buf[1024]; + + i = 0; + while (*p && *p != ':') + name_buf[i++] = *p++; + name_buf[i] = 0; + + p++; // skip ':' + while (isspace(*p)) p++; // skip spaces + + i = 0; + while (*p && *p != '\r' && *p != '\n') // read to end of header line + value_buf[i++] = *p++; + value_buf[i] = 0; + + if (!_stricmp(name_buf, "Set-Cookie")) { + ParseCookie(value_buf); + } + else { + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, value_buf); + if (param) + headers.append(param); + } + + while (*p && *p != '\n') + p++; + + if (*p == '\n') p++; + } + + if (*p == '\n') p++; + content = p; +} + +void +HttpResponse::ParseCookie(const char* param) +{ + const char* p = param; + + while (p && *p) { + while (isspace(*p)) p++; + + // just ignore reserved attributes + if (*p == '$') { + while (*p && !isspace(*p) && *p != ';') p++; + + if (*p == ';') + p++; + } + + // found a cookie! + else if (isalpha(*p)) { + char name[1024]; + char data[1024]; + + char* d = name; + while (*p && *p != '=') + *d++ = *p++; + *d = 0; + + if (*p == '=') + p++; + + if (*p == '"') + p++; + + d = data; + while (*p && *p != '"' && *p != ';') + *d++ = *p++; + *d = 0; + + if (*p == '"') + p++; + + if (*p == ';') + p++; + + // ignore the version attribute + if (_stricmp(name, "version")) { + HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, data); + if (param) + cookies.append(param); + } + } + + // this shouldn't happen - abandon the parse + else { + return; + } + } +} + |