nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@1: #include "http.h" nuclear@1: nuclear@3: nuclear@3: const char *http_method_str[] = { nuclear@3: "", nuclear@3: "OPTIONS", nuclear@3: "GET", nuclear@3: "HEAD", nuclear@3: "POST", nuclear@3: "PUT", nuclear@3: "DELETE", nuclear@3: "TRACE", nuclear@3: "CONNECT", nuclear@3: 0 nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: /* HTTP 1xx message strings */ nuclear@3: const char *http_msg1xx[] = { nuclear@3: "Continue", /* 100 */ nuclear@3: "Switching Protocols" /* 101 */ nuclear@3: }; nuclear@3: nuclear@3: /* HTTP 2xx message strings */ nuclear@3: const char *http_msg2xx[] = { nuclear@3: "OK", /* 200 */ nuclear@3: "Created", /* 201 */ nuclear@3: "Accepted", /* 202 */ nuclear@3: "Non-Authoritative Information", /* 203 */ nuclear@3: "No Content", /* 204 */ nuclear@3: "Reset Content", /* 205 */ nuclear@3: "Partial Content" /* 206 */ nuclear@3: }; nuclear@3: nuclear@3: /* HTTP 3xx message strings */ nuclear@3: const char *http_msg3xx[] = { nuclear@3: "Multiple Choices", /* 300 */ nuclear@3: "Moved Permanently", /* 301 */ nuclear@3: "Found", /* 302 */ nuclear@3: "See Other", /* 303 */ nuclear@3: "Not Modified", /* 304 */ nuclear@3: "Use Proxy", /* 305 */ nuclear@3: "", /* 306 is undefined? */ nuclear@3: "Temporary Redirect" /* 307 */ nuclear@3: }; nuclear@3: nuclear@3: /* HTTP 4xx error strings */ nuclear@3: const char *http_msg4xx[] = { nuclear@3: "Bad Request", /* 400 */ nuclear@3: "Unauthorized", /* 401 */ nuclear@3: "What the Fuck?", /* 402 */ nuclear@3: "Forbidden", /* 403 */ nuclear@3: "Not Found", /* 404 */ nuclear@3: "Method Not Allowed", /* 405 */ nuclear@3: "Not Acceptable", /* 406 */ nuclear@3: "Proxy Authentication Required", /* 407 */ nuclear@3: "Request Time-out", /* 408 */ nuclear@3: "Conflict", /* 409 */ nuclear@3: "Gone", /* 410 */ nuclear@3: "Length Required", /* 411 */ nuclear@3: "Precondition Failed", /* 412 */ nuclear@3: "Request Entity Too Large", /* 413 */ nuclear@3: "Request-URI Too Large", /* 414 */ nuclear@3: "Unsupported Media Type", /* 415 */ nuclear@3: "Request range not satisfiable", /* 416 */ nuclear@3: "Expectation Failed" /* 417 */ nuclear@3: }; nuclear@3: nuclear@3: /* HTTP 5xx error strings */ nuclear@3: const char *http_msg5xx[] = { nuclear@3: "Internal Server Error", /* 500 */ nuclear@3: "Not Implemented", /* 501 */ nuclear@3: "Bad Gateway", /* 502 */ nuclear@3: "Service Unavailable", /* 503 */ nuclear@3: "Gateway Time-out", /* 504 */ nuclear@3: "HTTP Version not supported" /* 505 */ nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: static enum http_method parse_method(const char *s); nuclear@3: nuclear@3: nuclear@2: int http_parse_header(struct http_req_header *hdr, const char *buf, int bufsz) nuclear@2: { nuclear@2: int i, nlines = 0; nuclear@2: char *rqline = 0; nuclear@3: char *method, *uri, *version, *ptr; nuclear@3: const char *startln, *endln; nuclear@3: nuclear@3: memset(hdr, 0, sizeof *hdr); nuclear@2: nuclear@2: for(i=1; i 4 && buf[i - 2] == '\n' && buf[i - 3] == '\r') { nuclear@3: hdr->body_offset = i + 1; nuclear@3: break; nuclear@3: } nuclear@2: } nuclear@2: } nuclear@2: nuclear@3: if(!rqline) { nuclear@3: return HTTP_HDR_PARTIAL; nuclear@3: } nuclear@2: nuclear@3: ptr = rqline; nuclear@3: while(*ptr && isspace(*ptr)) ++ptr; nuclear@3: method = ptr; nuclear@2: nuclear@3: /* parse the request line */ nuclear@3: while(*ptr && !isspace(*ptr)) ++ptr; nuclear@3: while(*ptr && isspace(*ptr)) *ptr++ = 0; nuclear@3: nuclear@3: uri = ptr; nuclear@3: while(*ptr && !isspace(*ptr)) ++ptr; nuclear@3: while(*ptr && isspace(*ptr)) *ptr++ = 0; nuclear@3: nuclear@3: version = ptr; nuclear@3: while(*ptr && !isspace(*ptr)) ++ptr; nuclear@3: while(*ptr && isspace(*ptr)) *ptr++ = 0; nuclear@3: nuclear@3: hdr->method = parse_method(method); nuclear@3: hdr->uri = strdup(uri); nuclear@3: if(sscanf(version, "HTTP/%d.%d", &hdr->ver_major, &hdr->ver_minor) != 2) { nuclear@3: fprintf(stderr, "warning: failed to parse HTTP version \"%s\"\n", version); nuclear@3: hdr->ver_major = 1; nuclear@3: hdr->ver_minor = 1; nuclear@3: } nuclear@3: nuclear@3: if(!(hdr->hdrfields = malloc(nlines * sizeof *hdr->hdrfields))) { nuclear@3: perror("failed to allocate memory for the header fields"); nuclear@3: return HTTP_HDR_NOMEM; nuclear@3: } nuclear@3: hdr->num_hdrfields = 0; nuclear@3: nuclear@3: startln = buf; nuclear@3: endln = buf; nuclear@3: for(i=1; ibody_offset; i++) { nuclear@3: if(buf[i] == '\n' && buf[i - 1] == '\r') { nuclear@3: int linesz; nuclear@3: endln = buf + i - 1; nuclear@3: linesz = endln - startln - 1; nuclear@3: nuclear@3: if(startln > buf) { /* skip first line */ nuclear@3: int idx = hdr->num_hdrfields++; nuclear@3: hdr->hdrfields[idx] = malloc(linesz + 1); nuclear@3: memcpy(hdr->hdrfields[idx], startln, linesz); nuclear@3: hdr->hdrfields[idx][linesz] = 0; nuclear@3: } nuclear@3: startln = endln = buf + i + 1; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: return HTTP_HDR_OK; nuclear@3: } nuclear@3: nuclear@3: void http_print_header(struct http_req_header *hdr) nuclear@3: { nuclear@3: int i; nuclear@3: nuclear@3: printf("HTTP request header\n"); nuclear@3: printf(" method: %s\n", http_method_str[hdr->method]); nuclear@3: printf(" uri: %s\n", hdr->uri); nuclear@3: printf(" version: %d.%d\n", hdr->ver_major, hdr->ver_minor); nuclear@3: printf(" fields (%d):\n", hdr->num_hdrfields); nuclear@3: nuclear@3: for(i=0; inum_hdrfields; i++) { nuclear@3: printf(" %s\n", hdr->hdrfields[i]); nuclear@3: } nuclear@3: putchar('\n'); nuclear@3: } nuclear@3: nuclear@3: void http_destroy_header(struct http_req_header *hdr) nuclear@3: { nuclear@3: int i; nuclear@3: nuclear@3: if(hdr->hdrfields) { nuclear@3: for(i=0; inum_hdrfields; i++) { nuclear@3: free(hdr->hdrfields[i]); nuclear@3: } nuclear@3: free(hdr->hdrfields); nuclear@3: } nuclear@3: free(hdr->uri); nuclear@2: } nuclear@2: nuclear@1: const char *http_strmsg(int code) nuclear@1: { nuclear@1: static const char **msgxxx[] = { nuclear@1: 0, http_msg1xx, http_msg2xx, http_msg3xx, http_msg4xx, http_msg5xx nuclear@1: }; nuclear@1: static int msgcount[] = { nuclear@1: 0, nuclear@1: sizeof http_msg1xx / sizeof *http_msg1xx, nuclear@1: sizeof http_msg2xx / sizeof *http_msg2xx, nuclear@1: sizeof http_msg3xx / sizeof *http_msg3xx, nuclear@1: sizeof http_msg4xx / sizeof *http_msg4xx, nuclear@1: sizeof http_msg5xx / sizeof *http_msg5xx nuclear@1: }; nuclear@1: nuclear@1: int type = code / 100; nuclear@1: int idx = code % 100; nuclear@1: nuclear@1: if(type < 1 || type >= sizeof msgxxx / sizeof *msgxxx) { nuclear@1: return "Invalid HTTP Status"; nuclear@1: } nuclear@1: nuclear@1: if(idx < 0 || idx >= msgcount[type]) { nuclear@1: return "Unknown HTTP Status"; nuclear@1: } nuclear@1: nuclear@1: return msgxxx[type][idx]; nuclear@1: } nuclear@3: nuclear@3: static enum http_method parse_method(const char *s) nuclear@3: { nuclear@3: int i; nuclear@3: for(i=0; http_method_str[i]; i++) { nuclear@3: if(strcmp(s, http_method_str[i]) == 0) { nuclear@3: return (enum http_method)i; nuclear@3: } nuclear@3: } nuclear@3: return HTTP_UNKNOWN; nuclear@3: }