📄 http.c
字号:
/* Copyright information is at the end of the file */#include <ctype.h>#include <assert.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <time.h>#include "xmlrpc_config.h"#include "mallocvar.h"#include "xmlrpc-c/string_int.h"#include "xmlrpc-c/abyss.h"#include "server.h"#include "session.h"#include "conn.h"#include "token.h"#include "date.h"#include "data.h"#include "abyss_info.h"#include "http.h"/*********************************************************************** Request Parser*********************************************************************//*********************************************************************** Request*********************************************************************/static voidinitRequestInfo(TRequestInfo * const requestInfoP, httpVersion const httpVersion, const char * const requestLine, TMethod const httpMethod, const char * const host, unsigned int const port, const char * const path, const char * const query) {/*---------------------------------------------------------------------------- Set up the request info structure. For information that is controlled by headers, use the defaults -- I.e. the value that applies if the request contains no applicable header.-----------------------------------------------------------------------------*/ requestInfoP->requestline = requestLine; requestInfoP->method = httpMethod; requestInfoP->host = host; requestInfoP->port = port; requestInfoP->uri = path; requestInfoP->query = query; requestInfoP->from = NULL; requestInfoP->useragent = NULL; requestInfoP->referer = NULL; requestInfoP->user = NULL; if (httpVersion.major > 1 || (httpVersion.major == 1 && httpVersion.minor >= 1)) requestInfoP->keepalive = TRUE; else requestInfoP->keepalive = FALSE;}static voidfreeRequestInfo(TRequestInfo * const requestInfoP) { if (requestInfoP->requestline) xmlrpc_strfree(requestInfoP->requestline); if (requestInfoP->user) xmlrpc_strfree(requestInfoP->user);}voidRequestInit(TSession * const sessionP, TConn * const connectionP) { time_t nowtime; sessionP->validRequest = false; /* Don't have valid request yet */ time(&nowtime); sessionP->date = *gmtime(&nowtime); sessionP->conn = connectionP; sessionP->responseStarted = FALSE; sessionP->chunkedwrite = FALSE; sessionP->chunkedwritemode = FALSE; ListInit(&sessionP->cookies); ListInit(&sessionP->ranges); TableInit(&sessionP->request_headers); TableInit(&sessionP->response_headers); sessionP->status = 0; /* No status from handler yet */ StringAlloc(&(sessionP->header));}voidRequestFree(TSession * const sessionP) { if (sessionP->validRequest) freeRequestInfo(&sessionP->request_info); ListFree(&sessionP->cookies); ListFree(&sessionP->ranges); TableFree(&sessionP->request_headers); TableFree(&sessionP->response_headers); StringFree(&(sessionP->header));}static voidreadRequestLine(TSession * const sessionP, char ** const requestLineP, uint16_t * const httpErrorCodeP) { *httpErrorCodeP = 0; /* Ignore CRLFs in the beginning of the request (RFC2068-P30) */ do { abyss_bool success; success = ConnReadHeader(sessionP->conn, requestLineP); if (!success) *httpErrorCodeP = 408; /* Request Timeout */ } while (!*httpErrorCodeP && (*requestLineP)[0] == '\0');}static voidunescapeUri(char * const uri, abyss_bool * const errorP) { char * x; char * y; x = y = uri; *errorP = FALSE; while (*x && !*errorP) { switch (*x) { case '%': { char c; ++x; c = tolower(*x++); if ((c >= '0') && (c <= '9')) c -= '0'; else if ((c >= 'a') && (c <= 'f')) c -= 'a' - 10; else *errorP = TRUE; if (!*errorP) { char d; d = tolower(*x++); if ((d >= '0') && (d <= '9')) d -= '0'; else if ((d >= 'a') && (d <= 'f')) d -= 'a' - 10; else *errorP = TRUE; if (!*errorP) *y++ = ((c << 4) | d); } } break; default: *y++ = *x++; break; } } *y = '\0';}static voidparseHostPort(char * const hostport, const char ** const hostP, unsigned short * const portP, uint16_t * const httpErrorCodeP) { char * colonPos; colonPos = strchr(hostport, ':'); if (colonPos) { const char * p; uint32_t port; *colonPos = '\0'; /* Split hostport at the colon */ *hostP = hostport; for (p = colonPos + 1, port = 0; isdigit(*p) && port < 65535; (port = port * 10 + (*p - '0')), ++p); *portP = port; if (*p || port == 0) *httpErrorCodeP = 400; /* Bad Request */ else *httpErrorCodeP = 0; } else { *hostP = hostport; *portP = 80; *httpErrorCodeP = 0; }}static voidparseRequestUri(char * const requestUri, const char ** const hostP, const char ** const pathP, const char ** const queryP, unsigned short * const portP, uint16_t * const httpErrorCodeP) {/*---------------------------------------------------------------------------- Parse the request URI (in the request line "GET http://www.myserver.com/myfile?parm HTTP/1.1", "http://www.myserver.com/myfile?parm" is the request URI). This destroys *requestUri and returns pointers into *requestUri! This is extremely ugly. We need to redo it with dynamically allocated storage. We should return individual malloc'ed strings.-----------------------------------------------------------------------------*/ abyss_bool error; unescapeUri(requestUri, &error); if (error) *httpErrorCodeP = 400; /* Bad Request */ else { char * requestUriNoQuery; /* The request URI with any query (the stuff marked by a question mark at the end of a request URI) chopped off. */ { /* Split requestUri at the question mark */ char * const qmark = strchr(requestUri, '?'); if (qmark) { *qmark = '\0'; *queryP = qmark + 1; } else *queryP = NULL; } requestUriNoQuery = requestUri; if (requestUriNoQuery[0] == '/') { *hostP = NULL; *pathP = requestUriNoQuery; *portP = 80; } else { if (!xmlrpc_strneq(requestUriNoQuery, "http://", 7)) *httpErrorCodeP = 400; /* Bad Request */ else { char * const hostportpath = &requestUriNoQuery[7]; char * const slashPos = strchr(hostportpath, '/'); char * hostport; if (slashPos) { char * p; *pathP = slashPos; /* Nul-terminate the host name. To make space for it, slide the whole name back one character. This moves it into the space now occupied by the end of "http://", which we don't need. */ for (p = hostportpath; *p != '/'; ++p) *(p-1) = *p; *(p-1) = '\0'; hostport = hostportpath - 1; *httpErrorCodeP = 0; } else { *pathP = "*"; hostport = hostportpath; *httpErrorCodeP = 0; } if (!*httpErrorCodeP) parseHostPort(hostport, hostP, portP, httpErrorCodeP); } } }}static voidparseRequestLine(char * const requestLine, TMethod * const httpMethodP, httpVersion * const httpVersionP, const char ** const hostP, unsigned short * const portP, const char ** const pathP, const char ** const queryP, abyss_bool * const moreLinesP, uint16_t * const httpErrorCodeP) {/*---------------------------------------------------------------------------- Modifies *header1 and returns pointers to its storage!-----------------------------------------------------------------------------*/ const char * httpMethodName; char * p; p = requestLine; /* Jump over spaces */ NextToken((const char **)&p); httpMethodName = GetToken(&p); if (!httpMethodName) *httpErrorCodeP = 400; /* Bad Request */ else { char * requestUri; if (xmlrpc_streq(httpMethodName, "GET")) *httpMethodP = m_get; else if (xmlrpc_streq(httpMethodName, "PUT")) *httpMethodP = m_put; else if (xmlrpc_streq(httpMethodName, "OPTIONS")) *httpMethodP = m_options; else if (xmlrpc_streq(httpMethodName, "DELETE")) *httpMethodP = m_delete; else if (xmlrpc_streq(httpMethodName, "POST")) *httpMethodP = m_post; else if (xmlrpc_streq(httpMethodName, "TRACE")) *httpMethodP = m_trace; else if (xmlrpc_streq(httpMethodName, "HEAD")) *httpMethodP = m_head; else *httpMethodP = m_unknown; /* URI and Query Decoding */ NextToken((const char **)&p); requestUri = GetToken(&p); if (!requestUri) *httpErrorCodeP = 400; /* Bad Request */ else { parseRequestUri(requestUri, hostP, pathP, queryP, portP, httpErrorCodeP); if (!*httpErrorCodeP) { const char * httpVersion; NextToken((const char **)&p); /* HTTP Version Decoding */ httpVersion = GetToken(&p); if (httpVersion) { uint32_t vmin, vmaj; if (sscanf(httpVersion, "HTTP/%d.%d", &vmaj, &vmin) != 2) *httpErrorCodeP = 400; /* Bad Request */ else { httpVersionP->major = vmaj; httpVersionP->minor = vmin; *httpErrorCodeP = 0; /* no error */ } *moreLinesP = TRUE; } else { /* There is no HTTP version, so this is a single line request. */ *httpErrorCodeP = 0; /* no error */ *moreLinesP = FALSE; } } } }}static voidstrtolower(char * const s) { char * t; t = &s[0]; while (*t) { *t = tolower(*t); ++t; }}static voidgetFieldNameToken(char ** const pP, char ** const fieldNameP, uint16_t * const httpErrorCodeP) { char * fieldName; NextToken((const char **)pP); fieldName = GetToken(pP); if (!fieldName)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -