fixed leaking open sockets when doing HTTP requests
[rocksndiamonds.git] / src / libgame / http.c
index b494ac42bd9d57d04bf84f14ed3d6189ef35c305..cfab11fc0dd7a872bf3169ea75d9c4bc4a92393c 100644 (file)
@@ -65,6 +65,22 @@ static void SetHttpResponseToDefaults(struct HttpResponse *response)
   response->status_text[0] = '\0';
 }
 
+struct HttpResponse *GetHttpResponseFromBuffer(void *buffer, int size)
+{
+  if (size > MAX_HTTP_BODY_SIZE)
+    return NULL;
+
+  struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
+
+  SetHttpResponseToDefaults(response);
+
+  strncpy(response->body, buffer, MAX_HTTP_BODY_SIZE);
+  response->body[MAX_HTTP_BODY_SIZE] = '\0';
+  response->body_size = MIN(size, MAX_HTTP_BODY_SIZE);
+
+  return response;
+}
+
 static boolean SetHTTPResponseCode(struct HttpResponse *response, char *buffer)
 {
   char *prefix = "HTTP/1.1 ";
@@ -154,18 +170,18 @@ 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");
 
@@ -189,9 +205,9 @@ static boolean DoHttpRequestExt(struct HttpRequest *request,
         (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());
@@ -199,7 +215,7 @@ static boolean DoHttpRequestExt(struct HttpRequest *request,
     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");
 
@@ -226,7 +242,7 @@ static boolean DoHttpRequestExt(struct HttpRequest *request,
   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))
   {
@@ -235,7 +251,7 @@ static boolean DoHttpRequestExt(struct HttpRequest *request,
     return FALSE;
   }
 
-  int recv_bytes = SDLNet_TCP_Recv(socket, recv_buffer, max_http_buffer_size);
+  int recv_bytes = SDLNet_TCP_Recv(*socket, recv_buffer, max_http_buffer_size);
 
   if (recv_bytes <= 0)
   {
@@ -270,9 +286,6 @@ static boolean DoHttpRequestExt(struct HttpRequest *request,
     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);
@@ -286,10 +299,23 @@ boolean DoHttpRequest(struct HttpRequest *request,
   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);
+  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);