Skip to content

Commit

Permalink
http: another cut at fixing HTTP framing
Browse files Browse the repository at this point in the history
For keep-alive connections it's neither sufficient to cut at the end of
header (since the rest of the response would leak into next request), nor
just fan out the current SSL frame (since the SSL framing is effectively
undefined and we don't know if we're done yet and with non-blocking reads
we're likely to just terminate too early).

So, let's just obey the Content-Length header. If it's missing (chunked
encoding or standards violation) then read until the EOF, but still
succeed if the header was complete. This way we're hopefully on the safe
side.
  • Loading branch information
lkundrak committed Sep 25, 2015
1 parent 77b821c commit 70dadda
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 5 deletions.
3 changes: 2 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ AM_INIT_AUTOMAKE([foreign subdir-objects])

# Checks for programs.
AC_PROG_CC
AC_GNU_SOURCE

AM_SILENT_RULES([yes])

Expand All @@ -33,7 +34,7 @@ AC_TYPE_UINT8_T
# Checks for library functions.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([bzero gethostbyname inet_ntoa memmove memset select socket strerror strstr strtol])
AC_CHECK_FUNCS([bzero gethostbyname inet_ntoa memmove memset memmem select socket strerror strstr strtol])

#AC_CONFIG_FILES([Makefile])
AC_OUTPUT(Makefile)
24 changes: 20 additions & 4 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ int http_receive(struct tunnel *tunnel, char **response)
char *buffer, *res;
int n = 0;
int bytes_read = 0;
int header_size = 0;
int content_size = 0;

buffer = malloc(BUFSZ);
if (buffer == NULL)
Expand All @@ -97,11 +99,25 @@ int http_receive(struct tunnel *tunnel, char **response)
(uint8_t *) buffer + bytes_read,
BUFSZ - 1 - bytes_read);
if (n > 0) {
char *eoh;

bytes_read += n;

if (bytes_read >= 4
&& !memcmp(&buffer[bytes_read - 4], "\r\n\r\n", 4))
break;
if (header_size) {
/* We saw the whole header, let's check if the body is done as well */
if (content_size && bytes_read >= header_size + content_size)
break;
} else {
/* Did we see the header end? Then get the body size. */
eoh = memmem (buffer, bytes_read, "\r\n\r\n", 4);
if (eoh) {
char *header = find_header (buffer, "Content-Length: ");

header_size = eoh - buffer + 4;
if (header)
content_size = atoi(header);
}
}

if (bytes_read == BUFSZ - 1) {
log_warn("Response too big\n");
Expand All @@ -111,7 +127,7 @@ int http_receive(struct tunnel *tunnel, char **response)
}
} while (n >= 0);

if (n < 0) {
if (!header_size) {
log_debug("Error reading from SSL connection (%s).\n",
err_ssl_str(n));
free(buffer);
Expand Down

0 comments on commit 70dadda

Please sign in to comment.