chibipub

experimental activitypub node in C
git clone git://jb55.com/chibipub
Log | Files | Refs | README | LICENSE

http.c (3164B)


      1 #include "http.h"
      2 #include "util.h"
      3 #include "parse.h"
      4 
      5 #include <stdio.h>
      6 #include <assert.h>
      7 
      8 
      9 void init_http_req(struct http_req *req)
     10 {
     11 	memset(req, 0, sizeof(*req));
     12 	init_errors(&req->errs);
     13 }
     14 
     15 static int parse_segment_with(struct parser *p, char **seg, char delim)
     16 {
     17 	char c;
     18 
     19 	*seg = (char*)p->arena.p;
     20 
     21 	while (1) {
     22 		if (!pull_byte(&p->cur, (unsigned char*)&c))
     23 			return 0;
     24 
     25 		if (c == delim) {
     26 			if (!push_byte(&p->arena, 0))
     27 				return 0;
     28 			return 1;
     29 		}
     30 
     31 		if (!push_byte(&p->arena, c))
     32 			return 0;
     33 	}
     34 
     35 	return 1;
     36 }
     37 
     38 static int parse_segment(struct parser *p, char **seg)
     39 {
     40 	return parse_segment_with(p, seg, ' ');
     41 }
     42 
     43 static int parse_last_segment(struct parser *p, char **seg)
     44 {
     45 	if (!parse_segment_with(p, seg, '\r'))
     46 		return 0;
     47 
     48 	consume_char(&p->cur, '\n');
     49 
     50 	return 1;
     51 }
     52 
     53 static int parse_header_name(struct parser *p, char **name)
     54 {
     55 	if (!parse_segment_with(p, name, ':'))
     56 		return 0;
     57 
     58 	return consume_char(&p->cur, ' ');
     59 }
     60 
     61 static int consume_crlf(struct cursor *cur)
     62 {
     63 	return consume_char(cur, '\r') && consume_char(cur, '\n');
     64 }
     65 
     66 static int parse_request_line(struct http_req *req, struct parser *p)
     67 {
     68 	if (!parse_segment(p, &req->method))
     69 		return 0;
     70 
     71 	if (!parse_segment(p, &req->path))
     72 		return 0;
     73 
     74 	return parse_last_segment(p, &req->ver);
     75 }
     76 
     77 static int parse_header(struct http_header **prev, struct parser *p)
     78 {
     79 	struct http_header next;
     80 	struct http_header *next_p;
     81 	next.next = NULL;
     82 
     83 	assert(prev);
     84 	assert(*prev == NULL || (*prev)->next == NULL);
     85 
     86 	if (!parse_header_name(p, &next.name))
     87 		return 0;
     88 
     89 	if (!parse_last_segment(p, &next.value))
     90 		return 0;
     91 
     92 	next_p = (struct http_header *)p->arena.p;
     93 
     94 	if (!push_data(&p->arena, (unsigned char*)&next, sizeof(next)))
     95 		return 0;
     96 
     97 	if (*prev == NULL)
     98 		*prev = next_p;
     99 	else
    100 		(*prev)->next = next_p;
    101 
    102 	return 1;
    103 }
    104 
    105 
    106 int parse_http_request(struct http_req *req, struct parser *p, int size)
    107 {
    108 	struct http_header **header;
    109 	struct cursor back;
    110 
    111 	if (!parse_request_line(req, p))
    112 		return 0;
    113 
    114 	header = &req->headers;
    115 
    116 	while (1) {
    117 		copy_cursor(&p->cur, &back);
    118 		if (!parse_header(header, p)) {
    119 			copy_cursor(&back, &p->cur);
    120 			break;
    121 		}
    122 		header = &(*header)->next;
    123 	}
    124 
    125 	if (!consume_crlf(&p->cur)) {
    126 		note_error(&req->errs, "pre-body crlf");
    127 		return 0;
    128 	}
    129 
    130 	req->body = p->cur.p;
    131 	req->body_len = size - (p->cur.p - p->cur.start);
    132 
    133 	return 1;
    134 }
    135 
    136 void print_http_request(struct http_req *req)
    137 {
    138 	struct http_header *header;
    139 	printf("%s %s %s\r\n", req->method, req->path, req->ver);
    140 	header = req->headers;
    141 	for (; header; header = header->next) {
    142 		printf("%s: %s\n", header->name, header->value);
    143 	}
    144 }
    145 
    146 int get_header(struct http_header *header, const char *match,
    147 		const char **result)
    148 {
    149 	for (; header; header = header->next) {
    150 		if (stricmp(header->name, match)) {
    151 			*result = header->value;
    152 			return 1;
    153 		}
    154 	}
    155 
    156 	return 0;
    157 }
    158 
    159 void http_write_status(struct http_req *req, const char *status)
    160 {
    161 	fprintf(req->client.socket_file, "HTTP/1.1 %s\r\n", status);
    162 }
    163 
    164 void http_write_header(struct http_req *req, const char *status)
    165 {
    166 	http_write_status(req, status);
    167 	fprintf(req->client.socket_file, "Connection: close\r\n");
    168 	fprintf(req->client.socket_file, "\r\n");
    169 }
    170