|  | @@ -1627,16 +1627,13 @@ int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
 | 
											
												
													
														|  |    return (int) total;
 |  |    return (int) total;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) {
 | 
											
												
													
														|  |    char mem[MG_BUF_LEN], *buf = mem;
 |  |    char mem[MG_BUF_LEN], *buf = mem;
 | 
											
												
													
														|  |    int len;
 |  |    int len;
 | 
											
												
													
														|  | -  va_list ap;
 |  | 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    // Print in a local buffer first, hoping that it is large enough to
 |  |    // Print in a local buffer first, hoping that it is large enough to
 | 
											
												
													
														|  |    // hold the whole message
 |  |    // hold the whole message
 | 
											
												
													
														|  | -  va_start(ap, fmt);
 |  | 
 | 
											
												
													
														|  |    len = vsnprintf(mem, sizeof(mem), fmt, ap);
 |  |    len = vsnprintf(mem, sizeof(mem), fmt, ap);
 | 
											
												
													
														|  | -  va_end(ap);
 |  | 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    if (len == 0) {
 |  |    if (len == 0) {
 | 
											
												
													
														|  |      // Do nothing. mg_printf(conn, "%s", "") was called.
 |  |      // Do nothing. mg_printf(conn, "%s", "") was called.
 | 
											
										
											
												
													
														|  | @@ -1647,9 +1644,7 @@ int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
 | 
											
												
													
														|  |    } else if (len > (int) sizeof(mem) &&
 |  |    } else if (len > (int) sizeof(mem) &&
 | 
											
												
													
														|  |               (buf = (char *) malloc(len + 1)) != NULL) {
 |  |               (buf = (char *) malloc(len + 1)) != NULL) {
 | 
											
												
													
														|  |      // Local buffer is not large enough, allocate big buffer on heap
 |  |      // Local buffer is not large enough, allocate big buffer on heap
 | 
											
												
													
														|  | -    va_start(ap, fmt);
 |  | 
 | 
											
												
													
														|  |      vsnprintf(buf, len + 1, fmt, ap);
 |  |      vsnprintf(buf, len + 1, fmt, ap);
 | 
											
												
													
														|  | -    va_end(ap);
 |  | 
 | 
											
												
													
														|  |      len = mg_write(conn, buf, (size_t) len);
 |  |      len = mg_write(conn, buf, (size_t) len);
 | 
											
												
													
														|  |      free(buf);
 |  |      free(buf);
 | 
											
												
													
														|  |    } else if (len > (int) sizeof(mem)) {
 |  |    } else if (len > (int) sizeof(mem)) {
 | 
											
										
											
												
													
														|  | @@ -1665,6 +1660,12 @@ int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
 | 
											
												
													
														|  |    return len;
 |  |    return len;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
 | 
											
												
													
														|  | 
 |  | +  va_list ap;
 | 
											
												
													
														|  | 
 |  | +  va_start(ap, fmt);
 | 
											
												
													
														|  | 
 |  | +  return mg_vprintf(conn, fmt, ap);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  // URL-decode input buffer into destination buffer.
 |  |  // URL-decode input buffer into destination buffer.
 | 
											
												
													
														|  |  // 0-terminate the destination buffer. Return the length of decoded data.
 |  |  // 0-terminate the destination buffer. Return the length of decoded data.
 | 
											
												
													
														|  |  // form-url-encoded data differs from URI encoding in a way that it
 |  |  // form-url-encoded data differs from URI encoding in a way that it
 | 
											
										
											
												
													
														|  | @@ -2811,7 +2812,7 @@ static void handle_file_request(struct mg_connection *conn, const char *path,
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    if (!mg_fopen(conn, path, "rb", filep)) {
 |  |    if (!mg_fopen(conn, path, "rb", filep)) {
 | 
											
												
													
														|  |      send_http_error(conn, 500, http_500_error,
 |  |      send_http_error(conn, 500, http_500_error,
 | 
											
												
													
														|  | -        "fopen(%s): %s", path, strerror(ERRNO));
 |  | 
 | 
											
												
													
														|  | 
 |  | +                    "fopen(%s): %s", path, strerror(ERRNO));
 | 
											
												
													
														|  |      return;
 |  |      return;
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  |    fclose_on_exec(filep);
 |  |    fclose_on_exec(filep);
 | 
											
										
											
												
													
														|  | @@ -2891,7 +2892,7 @@ static int is_valid_http_method(const char *method) {
 | 
											
												
													
														|  |  // This function modifies the buffer by NUL-terminating
 |  |  // This function modifies the buffer by NUL-terminating
 | 
											
												
													
														|  |  // HTTP request components, header names and header values.
 |  |  // HTTP request components, header names and header values.
 | 
											
												
													
														|  |  static int parse_http_message(char *buf, int len, struct mg_request_info *ri) {
 |  |  static int parse_http_message(char *buf, int len, struct mg_request_info *ri) {
 | 
											
												
													
														|  | -  int request_length = get_request_len(buf, len);
 |  | 
 | 
											
												
													
														|  | 
 |  | +  int is_request, request_length = get_request_len(buf, len);
 | 
											
												
													
														|  |    if (request_length > 0) {
 |  |    if (request_length > 0) {
 | 
											
												
													
														|  |      // Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
 |  |      // Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
 | 
											
												
													
														|  |      ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
 |  |      ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
 | 
											
										
											
												
													
														|  | @@ -2906,28 +2907,20 @@ static int parse_http_message(char *buf, int len, struct mg_request_info *ri) {
 | 
											
												
													
														|  |      ri->request_method = skip(&buf, " ");
 |  |      ri->request_method = skip(&buf, " ");
 | 
											
												
													
														|  |      ri->uri = skip(&buf, " ");
 |  |      ri->uri = skip(&buf, " ");
 | 
											
												
													
														|  |      ri->http_version = skip(&buf, "\r\n");
 |  |      ri->http_version = skip(&buf, "\r\n");
 | 
											
												
													
														|  | -    parse_http_headers(&buf, ri);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    if (((is_request = is_valid_http_method(ri->request_method)) &&
 | 
											
												
													
														|  | 
 |  | +         memcmp(ri->http_version, "HTTP/", 5) != 0) ||
 | 
											
												
													
														|  | 
 |  | +        (!is_request && memcmp(ri->request_method, "HTTP/", 5)) != 0) {
 | 
											
												
													
														|  | 
 |  | +      request_length = -1;
 | 
											
												
													
														|  | 
 |  | +    } else {
 | 
											
												
													
														|  | 
 |  | +      if (is_request) {
 | 
											
												
													
														|  | 
 |  | +        ri->http_version += 5;
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      parse_http_headers(&buf, ri);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  |    return request_length;
 |  |    return request_length;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -static int parse_http_request(char *buf, int len, struct mg_request_info *ri) {
 |  | 
 | 
											
												
													
														|  | -  int result = parse_http_message(buf, len, ri);
 |  | 
 | 
											
												
													
														|  | -  if (result > 0 &&
 |  | 
 | 
											
												
													
														|  | -      is_valid_http_method(ri->request_method) &&
 |  | 
 | 
											
												
													
														|  | -      !strncmp(ri->http_version, "HTTP/", 5)) {
 |  | 
 | 
											
												
													
														|  | -    ri->http_version += 5;   // Skip "HTTP/"
 |  | 
 | 
											
												
													
														|  | -  } else {
 |  | 
 | 
											
												
													
														|  | -    result = -1;
 |  | 
 | 
											
												
													
														|  | -  }
 |  | 
 | 
											
												
													
														|  | -  return result;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static int parse_http_response(char *buf, int len, struct mg_request_info *ri) {
 |  | 
 | 
											
												
													
														|  | -  int result = parse_http_message(buf, len, ri);
 |  | 
 | 
											
												
													
														|  | -  return result > 0 && !strncmp(ri->request_method, "HTTP/", 5) ? result : -1;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  |  // Keep reading the input (either opened file descriptor fd, or socket sock,
 |  |  // Keep reading the input (either opened file descriptor fd, or socket sock,
 | 
											
												
													
														|  |  // or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
 |  |  // or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
 | 
											
												
													
														|  |  // buffer (which marks the end of HTTP request). Buffer buf may already
 |  |  // buffer (which marks the end of HTTP request). Buffer buf may already
 | 
											
										
											
												
													
														|  | @@ -4734,74 +4727,109 @@ void mg_close_connection(struct mg_connection *conn) {
 | 
											
												
													
														|  |    free(conn);
 |  |    free(conn);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -struct mg_connection *mg_connect(struct mg_context *ctx,
 |  | 
 | 
											
												
													
														|  | -                                 const char *host, int port, int use_ssl) {
 |  | 
 | 
											
												
													
														|  | -  struct mg_connection *newconn = NULL;
 |  | 
 | 
											
												
													
														|  | 
 |  | +struct mg_connection *mg_connect(const char *host, int port, int use_ssl,
 | 
											
												
													
														|  | 
 |  | +                                 char *ebuf, size_t ebuf_len) {
 | 
											
												
													
														|  | 
 |  | +  static struct mg_context fake_ctx;
 | 
											
												
													
														|  | 
 |  | +  struct mg_connection *conn = NULL;
 | 
											
												
													
														|  |    struct sockaddr_in sin;
 |  |    struct sockaddr_in sin;
 | 
											
												
													
														|  |    struct hostent *he;
 |  |    struct hostent *he;
 | 
											
												
													
														|  | 
 |  | +  SSL_CTX *ssl = NULL;
 | 
											
												
													
														|  |    int sock;
 |  |    int sock;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  if (use_ssl && (ctx == NULL || ctx->client_ssl_ctx == NULL)) {
 |  | 
 | 
											
												
													
														|  | -    cry(fc(ctx), "%s: SSL is not initialized", __func__);
 |  | 
 | 
											
												
													
														|  | 
 |  | +  if (host == NULL) {
 | 
											
												
													
														|  | 
 |  | +    snprintf(ebuf, ebuf_len, "%s", "NULL host");
 | 
											
												
													
														|  | 
 |  | +  } else if (use_ssl && SSLv23_client_method == NULL) {
 | 
											
												
													
														|  | 
 |  | +    snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized");
 | 
											
												
													
														|  | 
 |  | +#ifndef NO_SSL
 | 
											
												
													
														|  | 
 |  | +  } else if (use_ssl && (ssl = SSL_CTX_new(SSLv23_client_method())) == NULL) {
 | 
											
												
													
														|  | 
 |  | +    snprintf(ebuf, ebuf_len, "SSL_CTX_new: %s", ssl_error());
 | 
											
												
													
														|  | 
 |  | +#endif // NO_SSL
 | 
											
												
													
														|  |    } else if ((he = gethostbyname(host)) == NULL) {
 |  |    } else if ((he = gethostbyname(host)) == NULL) {
 | 
											
												
													
														|  | -    cry(fc(ctx), "%s: gethostbyname(%s): %s", __func__, host, strerror(ERRNO));
 |  | 
 | 
											
												
													
														|  | 
 |  | +    snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO));
 | 
											
												
													
														|  |    } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
 |  |    } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
 | 
											
												
													
														|  | -    cry(fc(ctx), "%s: socket: %s", __func__, strerror(ERRNO));
 |  | 
 | 
											
												
													
														|  | 
 |  | +    snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO));
 | 
											
												
													
														|  |    } else {
 |  |    } else {
 | 
											
												
													
														|  |      sin.sin_family = AF_INET;
 |  |      sin.sin_family = AF_INET;
 | 
											
												
													
														|  |      sin.sin_port = htons((uint16_t) port);
 |  |      sin.sin_port = htons((uint16_t) port);
 | 
											
												
													
														|  |      sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
 |  |      sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
 | 
											
												
													
														|  |      if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
 |  |      if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
 | 
											
												
													
														|  | -      cry(fc(ctx), "%s: connect(%s:%d): %s", __func__, host, port,
 |  | 
 | 
											
												
													
														|  | -          strerror(ERRNO));
 |  | 
 | 
											
												
													
														|  | 
 |  | +      snprintf(ebuf, ebuf_len, "connect(%s:%d): %s",
 | 
											
												
													
														|  | 
 |  | +               host, port, strerror(ERRNO));
 | 
											
												
													
														|  |        closesocket(sock);
 |  |        closesocket(sock);
 | 
											
												
													
														|  | -    } else if ((newconn = (struct mg_connection *)
 |  | 
 | 
											
												
													
														|  | -                calloc(1, sizeof(*newconn))) == NULL) {
 |  | 
 | 
											
												
													
														|  | -      cry(fc(ctx), "%s: calloc: %s", __func__, strerror(ERRNO));
 |  | 
 | 
											
												
													
														|  | 
 |  | +    } else if ((conn = (struct mg_connection *)
 | 
											
												
													
														|  | 
 |  | +                calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
 | 
											
												
													
														|  | 
 |  | +      snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO));
 | 
											
												
													
														|  |        closesocket(sock);
 |  |        closesocket(sock);
 | 
											
												
													
														|  |      } else {
 |  |      } else {
 | 
											
												
													
														|  | -      newconn->ctx = ctx;
 |  | 
 | 
											
												
													
														|  | -      newconn->client.sock = sock;
 |  | 
 | 
											
												
													
														|  | -      newconn->client.rsa.sin = sin;
 |  | 
 | 
											
												
													
														|  | -      newconn->client.is_ssl = use_ssl;
 |  | 
 | 
											
												
													
														|  | 
 |  | +      conn->buf_size = MAX_REQUEST_SIZE;
 | 
											
												
													
														|  | 
 |  | +      conn->buf = (char *) (conn + 1);
 | 
											
												
													
														|  | 
 |  | +      conn->ctx = &fake_ctx;
 | 
											
												
													
														|  | 
 |  | +      conn->client.sock = sock;
 | 
											
												
													
														|  | 
 |  | +      conn->client.rsa.sin = sin;
 | 
											
												
													
														|  | 
 |  | +      conn->client.is_ssl = use_ssl;
 | 
											
												
													
														|  |        if (use_ssl) {
 |  |        if (use_ssl) {
 | 
											
												
													
														|  | -        sslize(newconn, ctx->client_ssl_ctx, SSL_connect);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        sslize(conn, ssl, SSL_connect);
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  | 
 |  | +  if (ssl != NULL) {
 | 
											
												
													
														|  | 
 |  | +    SSL_CTX_free(ssl);
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  return newconn;
 |  | 
 | 
											
												
													
														|  | 
 |  | +  return conn;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -FILE *mg_fetch(struct mg_context *ctx, const char *url, const char *path,
 |  | 
 | 
											
												
													
														|  | -               char *buf, size_t buf_len, struct mg_request_info *ri) {
 |  | 
 | 
											
												
													
														|  | -  struct mg_connection *newconn;
 |  | 
 | 
											
												
													
														|  | -  int n, req_length, data_length, port;
 |  | 
 | 
											
												
													
														|  | -  char host[1025], proto[10], buf2[MG_BUF_LEN];
 |  | 
 | 
											
												
													
														|  | -  FILE *fp = NULL;
 |  | 
 | 
											
												
													
														|  | 
 |  | +static int is_valid_uri(const char *uri) {
 | 
											
												
													
														|  | 
 |  | +  // Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
 | 
											
												
													
														|  | 
 |  | +  // URI can be an asterisk (*) or should start with slash.
 | 
											
												
													
														|  | 
 |  | +  return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0');
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  if (sscanf(url, "%9[htps]://%1024[^:]:%d/%n", proto, host, &port, &n) == 3) {
 |  | 
 | 
											
												
													
														|  | -  } else if (sscanf(url, "%9[htps]://%1024[^/]/%n", proto, host, &n) == 2) {
 |  | 
 | 
											
												
													
														|  | -    port = mg_strcasecmp(proto, "https") == 0 ? 443 : 80;
 |  | 
 | 
											
												
													
														|  | 
 |  | +static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) {
 | 
											
												
													
														|  | 
 |  | +  const char *cl;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  ebuf[0] = '\0';
 | 
											
												
													
														|  | 
 |  | +  reset_per_request_attributes(conn);
 | 
											
												
													
														|  | 
 |  | +  conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size,
 | 
											
												
													
														|  | 
 |  | +                                   &conn->data_len);
 | 
											
												
													
														|  | 
 |  | +  assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
 | 
											
												
													
														|  | 
 |  | +    snprintf(ebuf, ebuf_len, "%s", "Request Too Large");
 | 
											
												
													
														|  | 
 |  | +  } if (conn->request_len <= 0) {
 | 
											
												
													
														|  | 
 |  | +    snprintf(ebuf, ebuf_len, "%s", "Client closed connection");
 | 
											
												
													
														|  | 
 |  | +  } else if (parse_http_message(conn->buf, conn->buf_size,
 | 
											
												
													
														|  | 
 |  | +                                &conn->request_info) <= 0) {
 | 
											
												
													
														|  | 
 |  | +    snprintf(ebuf, ebuf_len, "Bad request: [%.*s]", conn->data_len, conn->buf);
 | 
											
												
													
														|  |    } else {
 |  |    } else {
 | 
											
												
													
														|  | -    cry(fc(ctx), "%s: invalid URL: [%s]", __func__, url);
 |  | 
 | 
											
												
													
														|  | -    return NULL;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    // Request is valid
 | 
											
												
													
														|  | 
 |  | +    if ((cl = get_header(&conn->request_info, "Content-Length")) != NULL) {
 | 
											
												
													
														|  | 
 |  | +      conn->content_len = strtoll(cl, NULL, 10);
 | 
											
												
													
														|  | 
 |  | +    } else if (!mg_strcasecmp(conn->request_info.request_method, "POST") ||
 | 
											
												
													
														|  | 
 |  | +               !mg_strcasecmp(conn->request_info.request_method, "PUT")) {
 | 
											
												
													
														|  | 
 |  | +      conn->content_len = -1;
 | 
											
												
													
														|  | 
 |  | +    } else {
 | 
											
												
													
														|  | 
 |  | +      conn->content_len = 0;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    conn->birth_time = time(NULL);
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  | 
 |  | +  return ebuf[0] == '\0';
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +struct mg_connection *mg_download(const char *host, int port, int use_ssl,
 | 
											
												
													
														|  | 
 |  | +                                  char *ebuf, size_t ebuf_len,
 | 
											
												
													
														|  | 
 |  | +                                  const char *fmt, ...) {
 | 
											
												
													
														|  | 
 |  | +  struct mg_connection *conn;
 | 
											
												
													
														|  | 
 |  | +  va_list ap;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  if ((newconn = mg_connect(ctx, host, port,
 |  | 
 | 
											
												
													
														|  | -                            !strcmp(proto, "https"))) == NULL) {
 |  | 
 | 
											
												
													
														|  | -    cry(fc(ctx), "%s: mg_connect(%s): %s", __func__, url, strerror(ERRNO));
 |  | 
 | 
											
												
													
														|  | 
 |  | +  va_start(ap, fmt);
 | 
											
												
													
														|  | 
 |  | +  ebuf[0] = '\0';
 | 
											
												
													
														|  | 
 |  | +  if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
 | 
											
												
													
														|  | 
 |  | +  } else if (mg_vprintf(conn, fmt, ap) <= 0) {
 | 
											
												
													
														|  | 
 |  | +    snprintf(ebuf, ebuf_len, "%s", "Error sending request");
 | 
											
												
													
														|  | 
 |  | +  } else if (!getreq(conn, ebuf, ebuf_len)) {
 | 
											
												
													
														|  |    } else {
 |  |    } else {
 | 
											
												
													
														|  | -    mg_printf(newconn, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", url + n, host);
 |  | 
 | 
											
												
													
														|  | -    data_length = 0;
 |  | 
 | 
											
												
													
														|  | -    req_length = read_request(NULL, newconn, buf, buf_len, &data_length);
 |  | 
 | 
											
												
													
														|  | -    if (req_length <= 0) {
 |  | 
 | 
											
												
													
														|  | -      cry(fc(ctx), "%s(%s): invalid HTTP reply", __func__, url);
 |  | 
 | 
											
												
													
														|  | -    } else if (parse_http_response(buf, req_length, ri) <= 0) {
 |  | 
 | 
											
												
													
														|  | -      cry(fc(ctx), "%s(%s): cannot parse HTTP headers", __func__, url);
 |  | 
 | 
											
												
													
														|  | -    } else if ((fp = fopen(path, "w+b")) == NULL) {
 |  | 
 | 
											
												
													
														|  | -      cry(fc(ctx), "%s: fopen(%s): %s", __func__, path, strerror(ERRNO));
 |  | 
 | 
											
												
													
														|  | -    } else {
 |  | 
 | 
											
												
													
														|  | 
 |  | +#if 0
 | 
											
												
													
														|  |        // Write chunk of data that may be in the user's buffer
 |  |        // Write chunk of data that may be in the user's buffer
 | 
											
												
													
														|  |        data_length -= req_length;
 |  |        data_length -= req_length;
 | 
											
												
													
														|  |        if (data_length > 0 &&
 |  |        if (data_length > 0 &&
 | 
											
										
											
												
													
														|  | @@ -4811,8 +4839,8 @@ FILE *mg_fetch(struct mg_context *ctx, const char *url, const char *path,
 | 
											
												
													
														|  |          fp = NULL;
 |  |          fp = NULL;
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
												
													
														|  |        // Read the rest of the response and write it to the file. Do not use
 |  |        // Read the rest of the response and write it to the file. Do not use
 | 
											
												
													
														|  | -      // mg_read() cause we didn't set newconn->content_len properly.
 |  | 
 | 
											
												
													
														|  | -      while (fp && (data_length = pull(0, newconn, buf2, sizeof(buf2))) > 0) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +      // mg_read() cause we didn't set conn->content_len properly.
 | 
											
												
													
														|  | 
 |  | +      while (fp && (data_length = pull(0, conn, buf2, sizeof(buf2))) > 0) {
 | 
											
												
													
														|  |          if (fwrite(buf2, 1, data_length, fp) != (size_t) data_length) {
 |  |          if (fwrite(buf2, 1, data_length, fp) != (size_t) data_length) {
 | 
											
												
													
														|  |            cry(fc(ctx), "%s: fwrite(%s): %s", __func__, path, strerror(ERRNO));
 |  |            cry(fc(ctx), "%s: fwrite(%s): %s", __func__, path, strerror(ERRNO));
 | 
											
												
													
														|  |            fclose(fp);
 |  |            fclose(fp);
 | 
											
										
											
												
													
														|  | @@ -4820,23 +4848,20 @@ FILE *mg_fetch(struct mg_context *ctx, const char *url, const char *path,
 | 
											
												
													
														|  |            break;
 |  |            break;
 | 
											
												
													
														|  |          }
 |  |          }
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -    mg_close_connection(newconn);
 |  | 
 | 
											
												
													
														|  | 
 |  | +#endif
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +  if (ebuf[0] != '\0' && conn != NULL) {
 | 
											
												
													
														|  | 
 |  | +    mg_close_connection(conn);
 | 
											
												
													
														|  | 
 |  | +    conn = NULL;
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  return fp;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static int is_valid_uri(const char *uri) {
 |  | 
 | 
											
												
													
														|  | -  // Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
 |  | 
 | 
											
												
													
														|  | -  // URI can be an asterisk (*) or should start with slash.
 |  | 
 | 
											
												
													
														|  | -  return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0');
 |  | 
 | 
											
												
													
														|  | 
 |  | +  return conn;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  static void process_new_connection(struct mg_connection *conn) {
 |  |  static void process_new_connection(struct mg_connection *conn) {
 | 
											
												
													
														|  |    struct mg_request_info *ri = &conn->request_info;
 |  |    struct mg_request_info *ri = &conn->request_info;
 | 
											
												
													
														|  |    int keep_alive_enabled, keep_alive, discard_len;
 |  |    int keep_alive_enabled, keep_alive, discard_len;
 | 
											
												
													
														|  | -  const char *cl;
 |  | 
 | 
											
												
													
														|  | 
 |  | +  char ebuf[100];
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
 |  |    keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
 | 
											
												
													
														|  |    keep_alive = 0;
 |  |    keep_alive = 0;
 | 
											
										
											
												
													
														|  | @@ -4845,38 +4870,18 @@ static void process_new_connection(struct mg_connection *conn) {
 | 
											
												
													
														|  |    // to crule42.
 |  |    // to crule42.
 | 
											
												
													
														|  |    conn->data_len = 0;
 |  |    conn->data_len = 0;
 | 
											
												
													
														|  |    do {
 |  |    do {
 | 
											
												
													
														|  | -    reset_per_request_attributes(conn);
 |  | 
 | 
											
												
													
														|  | -    conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size,
 |  | 
 | 
											
												
													
														|  | -                                     &conn->data_len);
 |  | 
 | 
											
												
													
														|  | -    assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
 |  | 
 | 
											
												
													
														|  | -    if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
 |  | 
 | 
											
												
													
														|  | -      send_http_error(conn, 413, "Request Too Large", "%s", "");
 |  | 
 | 
											
												
													
														|  | -      return;
 |  | 
 | 
											
												
													
														|  | -    } if (conn->request_len <= 0) {
 |  | 
 | 
											
												
													
														|  | -      return;  // Remote end closed the connection
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -    if (parse_http_request(conn->buf, conn->buf_size, ri) <= 0 ||
 |  | 
 | 
											
												
													
														|  | -        !is_valid_uri(ri->uri)) {
 |  | 
 | 
											
												
													
														|  | -      // Do not put garbage in the access log, just send it back to the client
 |  | 
 | 
											
												
													
														|  | -      send_http_error(conn, 400, "Bad Request",
 |  | 
 | 
											
												
													
														|  | -          "Cannot parse HTTP request: [%.*s]", conn->data_len, conn->buf);
 |  | 
 | 
											
												
													
														|  | -      conn->must_close = 1;
 |  | 
 | 
											
												
													
														|  | 
 |  | +    if (!getreq(conn, ebuf, sizeof(ebuf))) {
 | 
											
												
													
														|  | 
 |  | +      send_http_error(conn, 500, "Server Error", "%s", ebuf);
 | 
											
												
													
														|  | 
 |  | +    } else if (!is_valid_uri(conn->request_info.uri)) {
 | 
											
												
													
														|  | 
 |  | +      snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);
 | 
											
												
													
														|  | 
 |  | +      send_http_error(conn, 400, "Bad Request", "%s", ebuf);
 | 
											
												
													
														|  |      } else if (strcmp(ri->http_version, "1.0") &&
 |  |      } else if (strcmp(ri->http_version, "1.0") &&
 | 
											
												
													
														|  |                 strcmp(ri->http_version, "1.1")) {
 |  |                 strcmp(ri->http_version, "1.1")) {
 | 
											
												
													
														|  | -      // Request seems valid, but HTTP version is strange
 |  | 
 | 
											
												
													
														|  | -      send_http_error(conn, 505, "HTTP version not supported", "%s", "");
 |  | 
 | 
											
												
													
														|  | -      log_access(conn);
 |  | 
 | 
											
												
													
														|  | -    } else {
 |  | 
 | 
											
												
													
														|  | -      // Request is valid, handle it
 |  | 
 | 
											
												
													
														|  | -      if ((cl = get_header(ri, "Content-Length")) != NULL) {
 |  | 
 | 
											
												
													
														|  | -        conn->content_len = strtoll(cl, NULL, 10);
 |  | 
 | 
											
												
													
														|  | -      } else if (!mg_strcasecmp(ri->request_method, "POST") ||
 |  | 
 | 
											
												
													
														|  | -                 !mg_strcasecmp(ri->request_method, "PUT")) {
 |  | 
 | 
											
												
													
														|  | -        conn->content_len = -1;
 |  | 
 | 
											
												
													
														|  | -      } else {
 |  | 
 | 
											
												
													
														|  | -        conn->content_len = 0;
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -      conn->birth_time = time(NULL);
 |  | 
 | 
											
												
													
														|  | 
 |  | +      snprintf(ebuf, sizeof(ebuf), "Bad HTTP version: [%s]", ri->http_version);
 | 
											
												
													
														|  | 
 |  | +      send_http_error(conn, 505, "Bad HTTP version", "%s", ebuf);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (ebuf[0] == '\0') {
 | 
											
												
													
														|  |        handle_request(conn);
 |  |        handle_request(conn);
 | 
											
												
													
														|  |        conn->request_info.ev_data = (void *) (long) conn->status_code;
 |  |        conn->request_info.ev_data = (void *) (long) conn->status_code;
 | 
											
												
													
														|  |        call_user(conn, MG_REQUEST_COMPLETE);
 |  |        call_user(conn, MG_REQUEST_COMPLETE);
 |