Esempio n. 1
0
void http_read(TCP_NODE * n, char *p_cmd, char *p_url, char *p_proto,
	       HASH * p_head)
{

	int code = 0;
	char lastmodified[DATE_SIZE];
	char resource[BUF_SIZE];
	char filename[BUF_SIZE];
	char range[BUF_SIZE];
	char *p_range = range;
	size_t filesize = 0;
	size_t content_length = 0;
	char keepalive[BUF_SIZE];
	const char *mimetype = NULL;

	/* Get protocol */
	if (!http_proto(n, p_proto)) {
		node_status(n, NODE_SHUTDOWN);
		goto END;
	}

	/* Get action */
	if (!http_action(n, p_cmd)) {
		node_status(n, NODE_SHUTDOWN);
		goto END;
	}

	/* Get resource */
	if (!http_resource(n, p_url, resource)) {
		node_status(n, NODE_SHUTDOWN);
		goto END;
	}

	/* Check Keep-Alive */
	n->keepalive = http_keepalive(p_head, keepalive);

	/* Compute filename */
	if (!http_filename(resource, filename)) {
		http_404(n, keepalive);
		info(_log, &n->c_addr, "404 %s", resource);
		goto END;
	}

	/* Compute file size */
	filesize = http_size_simple(filename);

	/* Compute mime type */
	mimetype = mime_find(filename);

	/* Last-Modified. */
	if (!http_resource_modified(filename, p_head, lastmodified)) {
		http_304(n, keepalive);
		info(_log, &n->c_addr, "304 %s", resource);
		goto END;
	}

	/* Range request? */
	if (http_range_detected(p_head, range)) {
		code = 206;
	} else {
		code = 200;
	}

	/* Normal 200-er request */
	if (code == 200) {
		info(_log, &n->c_addr, "200 %s", resource);
		http_200(n, lastmodified, filename, filesize, keepalive,
			 mimetype);
		http_body(n, filename, filesize);
		goto END;
	}

	/* Check for 'bytes=' in range. Fallback to 200 if necessary. */
	if (!http_range_prepare(&p_range)) {
		info(_log, &n->c_addr, "200 %s", resource);
		http_200(n, lastmodified, filename, filesize, keepalive,
			 mimetype);
		http_body(n, filename, filesize);
		goto END;
	}

	/* multipart/byteranges */
	if (!http_range_multipart(p_range)) {
		RESPONSE *r_head = NULL, *r_file = NULL;

		/* Header */
		if ((r_head =
		     resp_put(n->response, RESPONSE_FROM_MEMORY)) == NULL) {
			node_status(n, NODE_SHUTDOWN);
			goto END;
		}

		/* File */
		if ((r_file =
		     resp_put(n->response, RESPONSE_FROM_FILE)) == NULL) {
			node_status(n, NODE_SHUTDOWN);
			goto END;
		}

		/* Parse range. */
		if (!http_range_simple(n, r_file, filename, filesize, p_range,
				       &content_length)) {
			node_status(n, NODE_SHUTDOWN);
			goto END;
		}

		/* Header with known content_length */
		http_206_simple(n, r_head, r_file, lastmodified, filename,
				filesize, content_length, keepalive, mimetype);

		info(_log, &n->c_addr, "206 %s [%s]", resource, range);
		goto END;
	} else {
		RESPONSE *r_head = NULL, *r_bottom = NULL, *r_zsyncbug = NULL;
		char boundary[12];

		/* Create boundary string */
		http_random(boundary, 12);

		/* Header */
		if ((r_head =
		     resp_put(n->response, RESPONSE_FROM_MEMORY)) == NULL) {
			node_status(n, NODE_SHUTDOWN);
			goto END;
		}

		/* zsync bug? One more \r\n between header and body. */
		if ((r_zsyncbug =
		     resp_put(n->response, RESPONSE_FROM_MEMORY)) == NULL) {
			node_status(n, NODE_SHUTDOWN);
			goto END;
		}

		/* Parse range. */
		if (!http_range_complex
		    (n, filename, filesize, mimetype, p_range, &content_length,
		     boundary)) {
			node_status(n, NODE_SHUTDOWN);
			goto END;
		}

		/* Bottom */
		if ((r_bottom =
		     resp_put(n->response, RESPONSE_FROM_MEMORY)) == NULL) {
			node_status(n, NODE_SHUTDOWN);
			goto END;
		}
		http_206_boundary_finish(r_bottom, &content_length, boundary);

		/* Header with known content_length */
		http_206_complex(n, r_head, lastmodified, filename,
				 filesize, content_length, boundary, keepalive);

		/* zsync bug? One more \r\n between header and body. */
		http_newline(r_zsyncbug, &content_length);

		info(_log, &n->c_addr, "206 %s [%s]", resource, range);

		goto END;
	}

	info(_log, &n->c_addr, "FIXME: HTTP parser end reached without result");
	node_status(n, NODE_SHUTDOWN);

 END:

	/* HTTP Pipeline: There is at least one more request to parse.
	 * Recursive request! Limited by the input buffer.
	 */
	if (n->pipeline != NODE_SHUTDOWN && n->recv_size > 0) {
		http_buf(n);
	}
}
Esempio n. 2
0
/* HTTP Functions */
int http_parse(http_t *http, char ch)
{
	int mode = 0;

	if (http->mode < MD_POST) {
		if (ch == '\r')
			return 0;
		if (ch == ' ' && http->idx == 0)
			return 0;
	}

	switch (http->mode) {
		/* HTTP Parsing */
		case MD_METHOD:
			if (ch == ' ')
				http_mode(http, MD_PATH, http->req_method);
			else if (http->idx < MAX_METHOD)
				http->req_method[http->idx++] = ch;
			return 0;

		case MD_PATH:
			if (ch == ' ')
				http_mode(http, MD_VERSION, http->req_path);
			else if (http->idx < MAX_PATH)
				http->req_path[http->idx++] = ch;
			return 0;

		case MD_VERSION:
			if (ch == '\n') {
				http_mode(http, MD_FIELD, http->req_version);
				http_open(http, http->req_method,
					      http->req_path,
					      http->req_version);
			}
			else if (http->idx < MAX_VERSION)
				http->req_version[http->idx++] = ch;
			return 0;

		case MD_FIELD:
			if (ch == '\n') {
				mode = http_body(http);
				http_mode(http, mode, http->hdr_field);
				switch (mode) {
					case MD_METHOD: return HTTP_DONE;
					case MD_SOCK:   return HTTP_SOCK;
					case MD_POST:   return HTTP_POST;
				}
			} else if (ch == ':')
				http_mode(http, MD_VALUE, http->hdr_field);
			else if (http->idx < MAX_FIELD)
				http->hdr_field[http->idx++] = ch;
			return 0;

		case MD_VALUE:
			if (ch == '\n') {
				http_mode(http, MD_FIELD, http->hdr_value);
				http_head(http, http->hdr_field, http->hdr_value);
			} else if (http->idx < MAX_VALUE)
				http->hdr_value[http->idx++] = ch;
			return 0;

		case MD_POST:
			return 0;

		case MD_SOCK:
			return 0;

		default:
			return 0;
	}
}