Ejemplo n.º 1
0
static int http_parse_first_line(struct http_connection *hc, struct evbuffer *evb)
{
	int ret = 0;
	char *line = NULL;
	size_t line_length = 0;

	line = evbuffer_readln(evb, &line_length, EVBUFFER_EOL_CRLF);
	if (line == NULL) {
		dbprintf("Could not read http first line\n");
		return -1;
	}
	if (line_length > 2048) {
		dbprintf("Http firstline too long(len > 2048)\n");
		goto failed;
	}

	ret = http_parse_request_line(hc, line);
	if (ret) {
		dbprintf("Could not parse http request line\n");
		goto failed;
	}

	free(line);

	return 0;
failed:
	if (line) {
		free(line);
	}
	return -1;
}
Ejemplo n.º 2
0
int http_receive_request(int sockfd, struct HttpRequest **received_request) {
    debug("http_receive_request");
    *received_request = NULL;
    char *method = NULL;
    char *resource = NULL;
    struct dict *headers = dict_create();
    int content_length = -1;
    char *payload = NULL;

    int http_error = HTTP_SUCCESS;
    char *line = NULL;

    if ((http_error = http_read_line(sockfd, &line)) != HTTP_SUCCESS) {
        goto error;
    }
    if ((http_error = http_parse_request_line(line, &method, &resource)) != HTTP_SUCCESS) {
        goto error;
    }
    free(line);

    if ((http_error = http_receive_headers(sockfd, headers)) != HTTP_SUCCESS) {
        goto error;
    }

    const char *l = dict_get_case(headers, "Content-Length");
    if (l != 0) {
        content_length = atoi(l);
    }

    if (content_length == -1 || content_length == 0) {
        debug("No or 0 content-length.");
        content_length = 0;
    } else {
        if ((http_error = http_receive_payload(sockfd, &payload, content_length)) != HTTP_SUCCESS) {
            goto error;
        }
    }

    // create and fill return object
    struct HttpRequest *request = (struct HttpRequest *)malloc(sizeof(struct HttpRequest));
    check_mem(request);
    request->method = method;
    request->resource = resource;
    request->headers = headers;
    request->content_length = content_length;
    request->payload = payload;

    *received_request = request;
    return HTTP_SUCCESS;

error:
    dict_free(headers); //TODO free entries
    free(method);
    free(resource);
    free(payload);
    free(line);
    assert(http_error != HTTP_SUCCESS);
    return http_error;
}
Ejemplo n.º 3
0
static void http_server_handler(int c)
{
    int code;
    struct socket_buffer sock;
    struct http_request request;
    char *buf;

    socket_buffer_init(&sock, c);
#if HAVE_OPENSSL
    if (o.ssl) {
        sock.fdn.ssl = new_ssl(sock.fdn.fd);
        if (SSL_accept(sock.fdn.ssl) != 1) {
            loguser("Failed SSL connection: %s\n",
                ERR_error_string(ERR_get_error(), NULL));
            fdinfo_close(&sock.fdn);
            return;
        }
    }
#endif

    code = http_read_request_line(&sock, &buf);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error reading Request-Line.\n");
        send_string(&sock.fdn, http_code2str(code));
        fdinfo_close(&sock.fdn);
        return;
    }
    if (o.debug > 1)
        logdebug("Request-Line: %s", buf);
    code = http_parse_request_line(buf, &request);
    free(buf);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error parsing Request-Line.\n");
        send_string(&sock.fdn, http_code2str(code));
        fdinfo_close(&sock.fdn);
        return;
    }

    if (!method_is_known(request.method)) {
        if (o.debug > 1)
            logdebug("Bad method: %s.\n", request.method);
        http_request_free(&request);
        send_string(&sock.fdn, http_code2str(405));
        fdinfo_close(&sock.fdn);
        return;
    }

    code = http_read_header(&sock, &buf);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error reading header.\n");
        http_request_free(&request);
        send_string(&sock.fdn, http_code2str(code));
        fdinfo_close(&sock.fdn);
        return;
    }
    if (o.debug > 1)
        logdebug("Header:\n%s", buf);
    code = http_request_parse_header(&request, buf);
    free(buf);
    if (code != 0) {
        if (o.verbose)
            logdebug("Error parsing header.\n");
        http_request_free(&request);
        send_string(&sock.fdn, http_code2str(code));
        fdinfo_close(&sock.fdn);
        return;
    }

    /* Check authentication. */
    if (o.proxy_auth) {
        struct http_credentials credentials;
        int ret, stale;

        if (http_header_get_proxy_credentials(request.header, &credentials) == NULL) {
            /* No credentials or a parsing error. */
            send_proxy_authenticate(&sock.fdn, 0);
            http_request_free(&request);
            fdinfo_close(&sock.fdn);
            return;
        }

        ret = check_auth(&request, &credentials, &stale);
        http_credentials_free(&credentials);
        if (!ret) {
            /* Password doesn't match. */
            /* RFC 2617, section 1.2: "If a proxy does not accept the
               credentials sent with a request, it SHOULD return a 407 (Proxy
               Authentication Required). */
            send_proxy_authenticate(&sock.fdn, stale);
            http_request_free(&request);
            fdinfo_close(&sock.fdn);
            return;
        }
    }

    if (strcmp(request.method, "CONNECT") == 0) {
        code = handle_connect(&sock, &request);
    } else if (strcmp(request.method, "GET") == 0
        || strcmp(request.method, "HEAD") == 0
        || strcmp(request.method, "POST") == 0) {
        code = handle_method(&sock, &request);
    } else {
        code = 500;
    }
    http_request_free(&request);

    if (code != 0) {
        send_string(&sock.fdn, http_code2str(code));
        fdinfo_close(&sock.fdn);
        return;
    }

    fdinfo_close(&sock.fdn);
}
Ejemplo n.º 4
0
//*************************************************
void *handle_http(void *arg) {
    http_request_t *request = (http_request_t *)arg;
    int fd = request->fd;
    int rcode = 0;
    int is_static;
    struct stat sbuf;
    char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[SHORTLINE], header_key[MAXLINE], header_value[MAXLINE];
    char filename[MAXLINE], cgiargs[MAXLINE];
    int n;
    
    /* Read request line and headers */
    while (1) {
        printf("[INFO] read from fd %d\n", fd);
        n = read(fd, request->last, (uint64_t)request->buf + MAX_BUF - (uint64_t)request->last);
        printf("[INFO] n = %d\n", n);
        if (n == 0) {
            goto err;
        }
        
        if (n < 0) {
            if (errno != EAGAIN) {
                log_err("read error, errno = %d", errno);
                goto err;
            }
            break;
        }
        
        request->last += n;
        
        rcode = http_parse_request_line(request);
        if (rcode == SERVER_AGAIN) {
            continue;
        }
        else if (rcode != SERVER_OK) {
            log_err("parse request line error, rcode = %d", rcode);
            goto err;
        }
        
        strncpy(method, request->request_start, request->method_end - request->request_start);
        strncpy(uri, request->uri_start, request->uri_end - request->uri_start);
        sprintf(version, "%d.%d", request->http_major, request->http_minor);
        
        if (request->method != HTTP_GET) {
        
            debug("error method: %s\n", method);
            debug("error uri: %s\n", uri);
            debug("error version: %s\n", version);
            clienterror(fd, method, "501", "Not Implemented",
                    "Server does not implement this method");
            return NULL;
        }
        
        debug("http request line");
        debug("method = %s", method);
        debug("uri = %s", uri);
        debug("version = %s", version);
        
        rcode = http_parse_request_body(request);
        if (rcode == SERVER_AGAIN) {
            continue;
        }
        else if (rcode != SERVER_OK) {
            log_err("parse request body error, rcode = %d", rcode);
            goto err;
        }
        
        debug("number of headers = %d", request->num_headers);
        
        if (request->num_headers > 0) {
            list_node_t *head = request->head->next;
            int i;
            for (i = 0; i < request->num_headers; i++) {
                http_header_t *header = (http_header_t *)head->ptr;
                memset(header_key, 0, sizeof(header_key));
                memset(header_value, 0, sizeof(header_value));
                memcpy(header_key, header->key_start, header->key_end - header->key_start);
                memcpy(header_value, header->value_start, header->value_end - header->value_start);
                debug("%s: %s", header_key, header_value);
                head = head->next;
            }
        }
        
        is_static = parse_uri(uri, filename, cgiargs);
        
        if (stat(filename, &sbuf) < 0) {
	        clienterror(fd, filename, "404", "Not found",
		        "Server couldn't find this file");
	        continue;
	    }

        if (is_static) {
	        if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
	            clienterror(fd, filename, "403", "Forbidden",
			        "Server couldn't read the file");
	            continue;
	        }
	        serve_static(fd, filename, sbuf.st_size);
        }
        
        goto close;
    }
    
    return NULL;

err:
close:
    debug("closing fd %d", fd);
    close(fd);
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
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;
}