📄 http.c
字号:
/*http.cCopyright (C) 1999 Lars Brinkhoff. See COPYING for terms and conditions.bug alert: parse_header() doesn't handle header fields that are extendedover multiple lines.*/#include <time.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "http.h"#include "common.h"static inline ssize_thttp_method (int fd, Http_destination *dest, Http_method method, ssize_t length){ char str[1024]; /* FIXME: possible buffer overflow */ Http_request *request; ssize_t n; if (fd == -1) { log_error ("http_method: fd == -1"); return -1; } n = 0; if (dest->proxy_name != NULL) n = sprintf (str, "http://%s:%d", dest->host_name, dest->host_port); sprintf (str + n, "/index.html?crap=%ld", time (NULL)); request = http_create_request (method, str, 1, 1); if (request == NULL) return -1; sprintf (str, "%s:%d", dest->host_name, dest->host_port); http_add_header (&request->header, "Host", str); if (length >= 0) { sprintf (str, "%d", length); http_add_header (&request->header, "Content-Length", str); } http_add_header (&request->header, "Connection", "close"); if (dest->proxy_authorization) { http_add_header (&request->header, "Proxy-Authorization", dest->proxy_authorization); } if (dest->user_agent) { http_add_header (&request->header, "User-Agent", dest->user_agent); } n = http_write_request (fd, request); http_destroy_request (request); return n;}ssize_thttp_get (int fd, Http_destination *dest){ return http_method (fd, dest, HTTP_GET, -1);}ssize_thttp_put (int fd, Http_destination *dest, size_t length){ return http_method (fd, dest, HTTP_PUT, (ssize_t)length);}ssize_thttp_post (int fd, Http_destination *dest, size_t length){ return http_method (fd, dest, HTTP_POST, (ssize_t)length);}inthttp_error_to_errno (int err){ /* Error codes taken from RFC2068. */ switch (err) { case -1: /* system error */ return errno; case -200: /* OK */ case -201: /* Created */ case -202: /* Accepted */ case -203: /* Non-Authoritative Information */ case -204: /* No Content */ case -205: /* Reset Content */ case -206: /* Partial Content */ return 0; case -400: /* Bad Request */ log_error ("http_error_to_errno: 400 bad request"); return EIO; case -401: /* Unauthorized */ log_error ("http_error_to_errno: 401 unauthorized"); return EACCES; case -403: /* Forbidden */ log_error ("http_error_to_errno: 403 forbidden"); return EACCES; case -404: /* Not Found */ log_error ("http_error_to_errno: 404 not found"); return ENOENT; case -411: /* Length Required */ log_error ("http_error_to_errno: 411 length required"); return EIO; case -413: /* Request Entity Too Large */ log_error ("http_error_to_errno: 413 request entity too large"); return EIO; case -505: /* HTTP Version Not Supported */ log_error ("http_error_to_errno: 413 HTTP version not supported"); return EIO; case -100: /* Continue */ case -101: /* Switching Protocols */ case -300: /* Multiple Choices */ case -301: /* Moved Permanently */ case -302: /* Moved Temporarily */ case -303: /* See Other */ case -304: /* Not Modified */ case -305: /* Use Proxy */ case -402: /* Payment Required */ case -405: /* Method Not Allowed */ case -406: /* Not Acceptable */ case -407: /* Proxy Autentication Required */ case -408: /* Request Timeout */ case -409: /* Conflict */ case -410: /* Gone */ case -412: /* Precondition Failed */ case -414: /* Request-URI Too Long */ case -415: /* Unsupported Media Type */ case -500: /* Internal Server Error */ case -501: /* Not Implemented */ case -502: /* Bad Gateway */ case -503: /* Service Unavailable */ case -504: /* Gateway Timeout */ log_error ("http_error_to_errno: HTTP error %d", err); return EIO; default: log_error ("http_error_to_errno: unknown error %d", err); return EIO; }}static Http_methodhttp_string_to_method (const char *method, size_t n){ if (strncmp (method, "GET", n) == 0) return HTTP_GET; if (strncmp (method, "PUT", n) == 0) return HTTP_PUT; if (strncmp (method, "POST", n) == 0) return HTTP_POST; if (strncmp (method, "OPTIONS", n) == 0) return HTTP_OPTIONS; if (strncmp (method, "HEAD", n) == 0) return HTTP_HEAD; if (strncmp (method, "DELETE", n) == 0) return HTTP_DELETE; if (strncmp (method, "TRACE", n) == 0) return HTTP_TRACE; return -1;}static const char *http_method_to_string (Http_method method){ switch (method) { case HTTP_GET: return "GET"; case HTTP_PUT: return "PUT"; case HTTP_POST: return "POST"; case HTTP_OPTIONS: return "OPTIONS"; case HTTP_HEAD: return "HEAD"; case HTTP_DELETE: return "DELETE"; case HTTP_TRACE: return "TRACE"; } return "(uknown)";}static ssize_tread_until (int fd, int ch, unsigned char **data){ unsigned char *buf, *buf2; ssize_t n, len, buf_size; *data = NULL; buf_size = 100; buf = malloc (buf_size); if (buf == NULL) { log_error ("read_until: out of memory"); return -1; } len = 0; while ((n = read_all (fd, buf + len, 1)) == 1) { if (buf[len++] == ch) break; if (len + 1 == buf_size) { buf_size *= 2; buf2 = realloc (buf, buf_size); if (buf2 == NULL) { log_error ("read_until: realloc failed"); free (buf); return -1; } buf = buf2; } } if (n <= 0) { free (buf); if (n == 0) log_error ("read_until: closed"); else log_error ("read_until: read error: %s", strerror (errno)); return n; } /* Shrink to minimum size + 1 in case someone wants to add a NUL. */ buf2 = realloc (buf, len + 1); if (buf2 == NULL) log_error ("read_until: realloc: shrink failed"); /* not fatal */ else buf = buf2; *data = buf; return len;}static inline Http_header *http_alloc_header (const char *name, const char *value){ Http_header *header; header = malloc (sizeof (Http_header)); if (header == NULL) return NULL; header->name = header->value = NULL; header->name = strdup (name); header->value = strdup (value); if (name == NULL || value == NULL) { if (name == NULL) free ((char *)name); if (value == NULL) free ((char *)value); free (header); return NULL; } return header;}Http_header *http_add_header (Http_header **header, const char *name, const char *value){ Http_header *new_header; new_header = http_alloc_header (name, value); if (new_header == NULL) return NULL; new_header->next = NULL; while (*header) header = &(*header)->next; *header = new_header; return new_header;}static ssize_tparse_header (int fd, Http_header **header){ unsigned char buf[2]; unsigned char *data; Http_header *h; size_t len; ssize_t n; *header = NULL; n = read_all (fd, buf, 2); if (n <= 0) return n; if (buf[0] == '\r' && buf[1] == '\n') return n; h = malloc (sizeof (Http_header)); if (h == NULL) { log_error ("parse_header: malloc failed"); return -1; } *header = h; h->name = NULL; h->value = NULL; n = read_until (fd, ':', &data); if (n <= 0) return n; data = realloc (data, n + 2); if (data == NULL) { log_error ("parse_header: realloc failed"); return -1; } memmove (data + 2, data, n); memcpy (data, buf, 2); n += 2; data[n - 1] = 0; h->name = data; len = n; n = read_until (fd, '\r', &data); if (n <= 0) return n; data[n - 1] = 0; h->value = data; len += n; n = read_until (fd, '\n', &data); if (n <= 0) return n; free (data); if (n != 1) { log_error ("parse_header: invalid line ending"); return -1; } len += n; log_verbose ("parse_header: %s:%s", h->name, h->value); n = parse_header (fd, &h->next); if (n <= 0) return n; len += n; return len;}static ssize_thttp_write_header (int fd, Http_header *header){ ssize_t n = 0, m; if (header == NULL) return write_all (fd, "\r\n", 2); m = write_all (fd, (void *)header->name, strlen (header->name)); if (m == -1) { return -1; } n += m; m = write_all (fd, ": ", 2); if (m == -1) { return -1; } n += m; m = write_all (fd, (void *)header->value, strlen (header->value)); if (m == -1) { return -1; } n += m; m = write_all (fd, "\r\n", 2); if (m == -1) { return -1; } n += m; m = http_write_header (fd, header->next); if (m == -1) { return -1; } n += m; return n;}static voidhttp_destroy_header (Http_header *header){ if (header == NULL) return; http_destroy_header (header->next); if (header->name) free ((char *)header->name); if (header->value) free ((char *)header->value); free (header);}static inline Http_response *http_allocate_response (const char *status_message){ Http_response *response; response = malloc (sizeof (Http_response)); if (response == NULL) return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -