Permalink
Browse files

Merge pull request #2 from gurjeet/better_http_handshake

Improve http_handshake in fork-echoserver.
  • Loading branch information...
2 parents 784eda2 + d108680 commit 16d7d7d1965b9f3211bfa19faaf2f00b89a0d893 @tatsuhiro-t tatsuhiro-t committed Apr 8, 2012
Showing with 78 additions and 4 deletions.
  1. +78 −4 examples/fork-echoserv.c
View
@@ -159,6 +159,80 @@ void create_accept_key(char *dst, const char *client_key)
dst[BASE64_ENCODE_RAW_LENGTH(20)] = '\0';
}
+/* We parse HTTP header lines of the format
+ * \r\nfield_name: value1, value2, ... \r\n
+ *
+ * If the caller is looking for a specific value, we return a pointer to the
+ * start of that value, else we simply return the start of values list.
+ */
+static char*
+http_header_find_field_value(char *header, char *field_name, char *value)
+{
+ char *header_end,
+ *field_start,
+ *field_end,
+ *next_crlf,
+ *value_start;
+ int field_name_len;
+
+ /* Pointer to the last character in the header */
+ header_end = header + strlen(header) - 1;
+
+ field_name_len = strlen(field_name);
+
+ field_start = header;
+
+ do{
+ field_start = strstr(field_start+1, field_name);
+
+ field_end = field_start + field_name_len - 1;
+
+ if(field_start != NULL
+ && field_start - header >= 2
+ && field_start[-2] == '\r'
+ && field_start[-1] == '\n'
+ && header_end - field_end >= 1
+ && field_end[1] == ':')
+ {
+ break; /* Found the field */
+ }
+ else
+ {
+ continue; /* This is not the one; keep looking. */
+ }
+ } while(field_start != NULL);
+
+ if(field_start == NULL)
+ return NULL;
+
+ /* Find the field terminator */
+ next_crlf = strstr(field_start, "\r\n");
+
+ /* A field is expected to end with \r\n */
+ if(next_crlf == NULL)
+ return NULL; /* Malformed HTTP header! */
+
+ /* If not looking for a value, then return a pointer to the start of values string */
+ if(value == NULL)
+ return field_end+2;
+
+ value_start = strstr(field_start, value);
+
+ /* Value not found */
+ if(value_start == NULL)
+ return NULL;
+
+ /* Found the value we're looking for */
+ if(value_start > next_crlf)
+ return NULL; /* ... but after the CRLF terminator of the field. */
+
+ /* The value we found should be properly delineated from the other tokens */
+ if(isalnum(value_start[-1]) || isalnum(value_start[strlen(value)]))
+ return NULL;
+
+ return value_start;
+}
+
/*
* Performs HTTP handshake. *fd* is the file descriptor of the
* connection to the client. This function returns 0 if it succeeds,
@@ -195,13 +269,13 @@ int http_handshake(int fd)
}
}
}
- if(strstr(header, "\r\nUpgrade: websocket\r\n") == NULL ||
- strstr(header, "\r\nConnection: Upgrade\r\n") == NULL ||
- (keyhdstart = strstr(header, "\r\nSec-WebSocket-Key:")) == NULL) {
+
+ if(http_header_find_field_value(header, "Upgrade", "websocket") == NULL ||
+ http_header_find_field_value(header, "Connection", "Upgrade") == NULL ||
+ (keyhdstart = http_header_find_field_value(header, "Sec-WebSocket-Key", NULL)) == NULL) {
fprintf(stderr, "HTTP Handshake: Missing required header fields");
return -1;
}
- keyhdstart += 20;
for(; *keyhdstart == ' '; ++keyhdstart);
keyhdend = keyhdstart;
for(; *keyhdend != '\r' && *keyhdend != ' '; ++keyhdend);

0 comments on commit 16d7d7d

Please sign in to comment.