Beispiel #1
0
int http_receive_headers(int sockfd, struct dict *headers) {
    int http_error = HTTP_SUCCESS;
    char *line = NULL;

    while (TRUE) {
        char *field_name;
        char *field_value;
        if ((http_error = http_read_line(sockfd, &line)) != HTTP_SUCCESS) {
            break;
        }
        if (strcmp(line, "") == 0) {
            debug("End of Http header");
            break;
        }
        if ((http_error = http_parse_header_line(line, &field_name, &field_value)) != HTTP_SUCCESS) {
            break;
        }
        free(line);
        dict_set(headers, field_name, field_value);
    }
    free(line);
    return http_error;
}
Beispiel #2
0
/*(*** http_eater */
void http_eater(void *htd, char *p, int m)
{
  http *ht;
  server *sv;

  ht = htd;
  sv = ht->ht_server;

#if DEBUG
  {
    char buf[75];
    int i;
    for(i = 0; i < m && i < sizeof(buf) - 1; i ++) {
      buf[i] = isprint(p[i]) ? p[i] : '?';
    }
    buf[i] = 0;
    log_msg(sv->sv_log, LOG_DEBUG, "Got line [%s]", buf);
  }
#endif

reswitch:
  switch(ht->ht_state) {
    case HTTP_REQUEST:
      /* XXX: parse request */
      {
        if(!http_parse_request_line(&ht->ht_hrl, p, m)) goto violation; /* MEMORY LEAK */

        log_msg(sv->sv_log,
                LOG_DEBUG,
                "Method is [%s] URI is [%s] major is [%s] minor is [%s]",
                ht->ht_hrl.hrl_method,
                ht->ht_hrl.hrl_uri,
                ht->ht_hrl.hrl_major,
                ht->ht_hrl.hrl_minor);

        ht->ht_state = HTTP_HEADER;
      }
      break;
    case HTTP_HEADER:
      if(m) {
        /* Non-empty header lines */
        http_release_header_line(&ht->ht_hhl);
        if(http_parse_header_line(&ht->ht_hhl, p, m)) {
          /* This is a nice header */
          ht->ht_state = HTTP_MORE_HEADERS;
        } else goto violation;
      } else {
        /* Empty line : headers finished */
        if(!http_process_header(ht)) goto violation;
        ht->ht_state = HTTP_BUILD_RESPONSE;
        goto reswitch;
      }
      break;
    case HTTP_MORE_HEADERS:
      if(m) {
        if(http_parse_header_continuation_line(&ht->ht_hhl, p, m))
          break; /* Stay in this state. */
        else {
          /* Not a continuation header. */
          /* Post current header. */
          if(!http_process_header(ht)) goto violation;
          ht->ht_state = HTTP_HEADER;
          goto reswitch;
        }
      } else {
        /* Empty line : headers finished */
        if(!http_process_header(ht)) goto violation;
        ht->ht_state = HTTP_BUILD_RESPONSE;
        goto reswitch;
      }
      break;
    case HTTP_BUILD_RESPONSE:
      /* Build response */
      {
        char *response;
        int response_length;
        char *content_type;
        size_t content_length;
        resource *rs;
        char *fn;

        if(!strcmp(ht->ht_hrl.hrl_method, "GET")) {
          fn = http_uri_to_filename(ht, ht->ht_hrl.hrl_uri);

          rs = resource_obtain(fn);
          if(!rs) {
            log_msg(sv->sv_log, LOG_ERROR, "Can't obtain %s (%s)", fn, strerror(errno));

            response_length =
              xasprintf(
                &response,
                "HTTP/1.1 404 Not Found\r\n"
                  "Content-Type: text/html\r\n"
                  "Connection: close\r\n"
                  "\r\n"
                  "<html>"
                  "<head><title>404 Not Found</title></head><body>"
                  "Unable to find resource %s (%s)."
                  "</body></html>", 
                fn,
                strerror(errno));
            ht->ht_state = HTTP_RESPONSE_ONLY;
          } else {
            content_type = rs->rs_mime_type;
            content_length = rs->rs_length;

            if(ht->ht_writer) { 
              writer_delete(ht->ht_writer);
              ht->ht_writer = 0;
            }
            ht->ht_resource = rs;

            response_length =
              xasprintf(
                &response,
                "HTTP/1.1 200 OK\r\n"
                  "Content-Type: %s\r\n"
                  "Connection: close\r\n"
                  "Content-Length: %d\r\n"
                  "\r\n",
                content_type,
                content_length);
            ht->ht_state = HTTP_RESPONDING;
          }
          xfree(fn);
        } else {
          response_length =
            xasprintf(
              &response,
              "HTTP/1.1 501 Not implemented\r\n"
                "Content-Type: text/html\r\n"
                "Connection: close\r\n"
                "\r\n"
                "<html>"
                "<head><title>501 Not implemented</title></head><body>"
                "Method %s is not supported by this server."
                "</body></html>", 
              ht->ht_hrl.hrl_method);
          ht->ht_state = HTTP_RESPONSE_ONLY;
        }
        ht->ht_response = response;
        ht->ht_writer = writer_create(response, response_length, response);
        demux_set_event_mask(sv->sv_demux, ht->ht_connection, POLLOUT); /* Stop reading */
      }
      break;
    case HTTP_RESPONSE_ONLY:
    case HTTP_RESPONDING:
      break;
    case HTTP_SERVING:
      break;
  }
  return;

violation:
  log_msg(sv->sv_log, LOG_ERROR, "HTTP protocol violation");
  demux_delete_connection(sv->sv_demux, ht->ht_connection);
  return;
}
Beispiel #3
0
int http_parser_input(void* parser, const void* data, size_t *bytes)
{
	enum { INPUT_NEEDMORE = 1, INPUT_DONE = 0, };

	int r;
	struct http_context *ctx;
	ctx = (struct http_context*)parser;

	// save raw data
	r = http_rawdata(ctx, data, *bytes);
	if(0 != r)
	{
		assert(r < 0);
		return r;
	}

	if(SM_FIRSTLINE <= ctx->stateM && ctx->stateM < SM_HEADER)
	{
		r = is_server_mode(ctx) ? http_parse_request_line(ctx) : http_parse_status_line(ctx);
	}

	if(SM_HEADER <= ctx->stateM && ctx->stateM < SM_BODY)
	{
		r = http_parse_header_line(ctx);
	}

	assert(r <= 0);
	if(SM_BODY <= ctx->stateM && ctx->stateM < SM_DONE)
	{
		if(is_transfer_encoding_chunked(ctx))
		{
			r = http_parse_chunked(ctx);
		}
		else
		{
			if(-1 == ctx->content_length)
			{
				if(is_server_mode(ctx))
				{
					ctx->content_length = 0;
					ctx->stateM = SM_DONE;
				}
				else
				{
					// H4.4 Message Length, section 5, server closing the connection
					// receive all until socket closed
					assert(!is_server_mode(ctx));
					if(0 == *bytes /*|| ctx->raw_size == ctx->offset*/)
					{
						ctx->content_length = ctx->raw_size - ctx->offset;
						ctx->stateM = SM_DONE;
					}
				}
			}
			else
			{
				assert(ctx->raw_size <= ctx->offset + ctx->content_length);
				if(ctx->raw_size >= ctx->offset + ctx->content_length)
					ctx->stateM = SM_DONE;
			}
		}
	}

	if(r < 0)
		return r;

	*bytes = 0;
	return ctx->stateM == SM_DONE ? INPUT_DONE : INPUT_NEEDMORE;
}