response->status_text[0] = '\0';
}
+struct HttpResponse *GetHttpResponseFromBuffer(void *buffer, int body_size)
+{
+ if (body_size > MAX_HTTP_BODY_SIZE)
+ return NULL;
+
+ struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
+
+ SetHttpResponseToDefaults(response);
+
+ memcpy(response->body, buffer, body_size);
+ response->body[body_size] = '\0';
+ response->body_size = body_size;
+
+ return response;
+}
+
static boolean SetHTTPResponseCode(struct HttpResponse *response, char *buffer)
{
char *prefix = "HTTP/1.1 ";
return TRUE;
}
+static int GetHttpResponse(TCPsocket socket, char *buffer, int max_buffer_size)
+{
+ char *buffer_ptr = buffer;
+ int buffer_left = max_buffer_size;
+ int buffer_size = 0;
+ int response_size = 0;
+
+ while (1)
+ {
+ // read as many bytes to the buffer as possible
+ int bytes = SDLNet_TCP_Recv(socket, buffer_ptr, buffer_left);
+
+ if (bytes <= 0)
+ {
+ SetHttpError("receiving response from server failed");
+
+ return -1;
+ }
+
+ buffer_ptr += bytes;
+ buffer_size += bytes;
+ buffer_left -= bytes;
+
+ // check if response size was already determined
+ if (response_size > 0)
+ {
+ // check if response data was completely received
+ if (buffer_size >= response_size)
+ break;
+
+ // continue reading response body from server
+ continue;
+ }
+
+ char *separator = "\r\n\r\n";
+ char *separator_start = strstr(buffer, separator);
+ int separator_size = strlen(separator);
+
+ // check if response header was completely received
+ if (separator_start == NULL)
+ {
+ // continue reading response header from server
+ continue;
+ }
+
+ char *content_length = "Content-Length: ";
+ char *content_length_start = strstr(buffer, content_length);
+ int head_size = separator_start - buffer;
+
+ // check if response header contains content length header
+ if (content_length_start == NULL ||
+ content_length_start >= buffer + head_size)
+ {
+ SetHttpError("receiving 'Content-Length' header from server failed");
+
+ return -1;
+ }
+
+ char *content_length_value = content_length_start + strlen(content_length);
+ char *content_length_end = strstr(content_length_value, "\r\n");
+
+ // check if content length header has line termination
+ if (content_length_end == NULL)
+ {
+ SetHttpError("receiving 'Content-Length' value from server failed");
+
+ return -1;
+ }
+
+ int value_len = content_length_end - content_length_value;
+ int max_value_len = 10;
+
+ // check if content length header has valid size
+ if (value_len > max_value_len)
+ {
+ SetHttpError("received invalid 'Content-Length' value from server");
+
+ return -1;
+ }
+
+ char value_str[value_len + 1];
+
+ strncpy(value_str, content_length_value, value_len);
+ value_str[value_len] = '\0';
+
+ int body_size = atoi(value_str);
+
+ response_size = head_size + separator_size + body_size;
+
+ // check if response data was completely received
+ if (buffer_size >= response_size)
+ break;
+ }
+
+ return buffer_size;
+}
+
static boolean DoHttpRequestExt(struct HttpRequest *request,
struct HttpResponse *response,
char *send_buffer,
char *recv_buffer,
- int max_http_buffer_size)
+ int max_http_buffer_size,
+ SDLNet_SocketSet *socket_set,
+ TCPsocket *socket)
{
- SDLNet_SocketSet socket_set;
- TCPsocket socket;
IPaddress ip;
int server_host;
SetHttpResponseToDefaults(response);
- socket_set = SDLNet_AllocSocketSet(1);
+ *socket_set = SDLNet_AllocSocketSet(1);
- if (socket_set == NULL)
+ if (*socket_set == NULL)
{
SetHttpError("cannot allocate socket set");
(server_host >> 8) & 0xff,
(server_host >> 0) & 0xff);
- socket = SDLNet_TCP_Open(&ip);
+ *socket = SDLNet_TCP_Open(&ip);
- if (socket == NULL)
+ if (*socket == NULL)
{
SetHttpError("cannot connect to host '%s': %s", request->hostname,
SDLNet_GetError());
return FALSE;
}
- if (SDLNet_TCP_AddSocket(socket_set, socket) == -1)
+ if (SDLNet_TCP_AddSocket(*socket_set, *socket) == -1)
{
SetHttpError("cannot add socket to socket set");
Debug("network:http", "client request:\n--- snip ---\n%s\n--- snip ---",
send_buffer);
- int send_bytes = SDLNet_TCP_Send(socket, send_buffer, strlen(send_buffer));
+ int send_bytes = SDLNet_TCP_Send(*socket, send_buffer, strlen(send_buffer));
if (send_bytes != strlen(send_buffer))
{
return FALSE;
}
- int recv_bytes = SDLNet_TCP_Recv(socket, recv_buffer, max_http_buffer_size);
+ int recv_bytes = GetHttpResponse(*socket, recv_buffer, max_http_buffer_size);
if (recv_bytes <= 0)
{
- SetHttpError("receiving response from server failed");
+ // HTTP error already set in GetHttpResponse()
return FALSE;
}
return FALSE;
}
- SDLNet_TCP_DelSocket(socket_set, socket);
- SDLNet_TCP_Close(socket);
-
Debug("network:http", "server response: %d %s",
response->status_code,
response->status_text);
boolean DoHttpRequest(struct HttpRequest *request,
struct HttpResponse *response)
{
- int max_http_buffer_size = MAX_HTTP_HEAD_SIZE + MAX_HTTP_BODY_SIZE;
- char *send_buffer = checked_malloc(max_http_buffer_size + 1);
- char *recv_buffer = checked_malloc(max_http_buffer_size + 1);
+ int max_http_buffer_size = MAX_HTTP_HEAD_SIZE + 2 + MAX_HTTP_BODY_SIZE + 1;
+ char *send_buffer = checked_malloc(max_http_buffer_size);
+ char *recv_buffer = checked_malloc(max_http_buffer_size);
+ SDLNet_SocketSet socket_set = NULL;
+ TCPsocket socket = NULL;
boolean success = DoHttpRequestExt(request, response,
send_buffer, recv_buffer,
- max_http_buffer_size);
+ max_http_buffer_size,
+ &socket_set, &socket);
+ if (socket_set != NULL)
+ {
+ if (socket != NULL)
+ {
+ SDLNet_TCP_DelSocket(socket_set, socket);
+ SDLNet_TCP_Close(socket);
+ }
+
+ SDLNet_FreeSocketSet(socket_set);
+ }
checked_free(send_buffer);
checked_free(recv_buffer);