HTTP decoding: allow blanks in URL paths YAZ-700
[yaz-moved-to-github.git] / src / http.c
index 397b7bd..642c3ad 100644 (file)
@@ -48,19 +48,14 @@ static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
                 break;
         }
         *headers = (Z_HTTP_Header *) odr_malloc(o, sizeof(**headers));
-        (*headers)->name = (char*) odr_malloc(o, i - po + 1);
-        memcpy ((*headers)->name, buf + po, i - po);
-        (*headers)->name[i - po] = '\0';
+        (*headers)->name = odr_strdupn(o, buf + po, i - po);
         i++;
         while (i < size-1 && buf[i] == ' ')
             i++;
         for (po = i; i < size-1 && !strchr("\r\n", buf[i]); i++)
             ;
 
-        (*headers)->value = (char*) odr_malloc(o, i - po + 1);
-        memcpy ((*headers)->value, buf + po, i - po);
-        (*headers)->value[i - po] = '\0';
-
+        (*headers)->value = odr_strdupn(o, buf + po, i - po);
         if (!yaz_strcasecmp((*headers)->name, "Transfer-Encoding")
             &&
             !yaz_strcasecmp((*headers)->value, "chunked"))
@@ -142,9 +137,7 @@ static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
         else
         {
             *content_len = size - i;
-            *content_buf = (char*) odr_malloc(o, *content_len + 1);
-            memcpy(*content_buf, buf + i, *content_len);
-            (*content_buf)[*content_len] = '\0';
+            *content_buf = odr_strdupn(o, buf + i, *content_len);
         }
     }
     return 1;
@@ -287,11 +280,8 @@ Z_GDU *z_get_HTTP_Request_host_path(ODR odr,
 
         if (cp0 && cp1)
         {
-            char *h = (char*) odr_malloc(odr, cp1 - cp0 + 1);
-            memcpy (h, cp0, cp1 - cp0);
-            h[cp1-cp0] = '\0';
-            z_HTTP_header_add(odr, &p->u.HTTP_Request->headers,
-                              "Host", h);
+            char *h = odr_strdupn(odr, cp0, cp1 - cp0);
+            z_HTTP_header_add(odr, &p->u.HTTP_Request->headers, "Host", h);
         }
     }
     return p;
@@ -314,11 +304,8 @@ Z_GDU *z_get_HTTP_Request_uri(ODR odr, const char *uri, const char *args,
 
     if (cp0 && cp1)
     {
-        char *h = (char*) odr_malloc(odr, cp1 - cp0 + 1);
-        memcpy (h, cp0, cp1 - cp0);
-        h[cp1-cp0] = '\0';
-        z_HTTP_header_add(odr, &p->u.HTTP_Request->headers,
-                          "Host", h);
+        char *h = odr_strdupn(odr, cp0, cp1 - cp0);
+        z_HTTP_header_add(odr, &p->u.HTTP_Request->headers, "Host", h);
     }
 
     if (!args)
@@ -340,7 +327,8 @@ Z_GDU *z_get_HTTP_Request_uri(ODR odr, const char *uri, const char *args,
     return p;
 }
 
-Z_GDU *z_get_HTTP_Response_details(ODR o, int code, const char *details)
+Z_GDU *z_get_HTTP_Response_server(ODR o, int code, const char *details,
+                                  const char *server, const char *server_url)
 {
     Z_GDU *p = (Z_GDU *) odr_malloc(o, sizeof(*p));
     Z_HTTP_Response *hres;
@@ -353,8 +341,7 @@ Z_GDU *z_get_HTTP_Response_details(ODR o, int code, const char *details)
     hres->content_buf = 0;
     hres->code = code;
     hres->version = "1.1";
-    z_HTTP_header_add(o, &hres->headers, "Server",
-                      "YAZ/" YAZ_VERSION);
+    z_HTTP_header_add(o, &hres->headers, "Server", server);
     if (code != 200)
     {
         const char *http_err = z_HTTP_errmsg(code);
@@ -366,13 +353,13 @@ Z_GDU *z_get_HTTP_Response_details(ODR o, int code, const char *details)
                 " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
                 "<HTML>\n"
                 " <HEAD>\n"
-                "  <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
+                "  <TITLE>%s</TITLE>\n"
                 " </HEAD>\n"
                 " <BODY>\n"
-                "  <P><A HREF=\"http://www.indexdata.com/yaz/\">YAZ</A> "
-                YAZ_VERSION "</P>\n"
+                "  <P><A HREF=\"%s\">%s</A></P>\n"
                 "  <P>Error: %d</P>\n"
-                "  <P>Description: %s</P>\n", code, http_err);
+                "  <P>Description: %s</P>\n", server, server_url, server,
+                code, http_err);
         if (details)
         {
             sprintf(hres->content_buf + strlen(hres->content_buf),
@@ -387,6 +374,12 @@ Z_GDU *z_get_HTTP_Response_details(ODR o, int code, const char *details)
     return p;
 }
 
+Z_GDU *z_get_HTTP_Response_details(ODR o, int code, const char *details)
+{
+    return z_get_HTTP_Response_server(o, code, details, "YAZ/" YAZ_VERSION,
+                                      "http://www.indexdata.com/yaz");
+}
+
 Z_GDU *z_get_HTTP_Response(ODR o, int code)
 {
     return z_get_HTTP_Response_details(o, code, 0);
@@ -489,10 +482,7 @@ int yaz_decode_http_response(ODR o, Z_HTTP_Response **hr_p)
     po = i = 5;
     while (i < size-2 && !strchr(" \r\n", buf[i]))
         i++;
-    hr->version = (char *) odr_malloc(o, i - po + 1);
-    if (i - po)
-        memcpy(hr->version, buf + po, i - po);
-    hr->version[i-po] = 0;
+    hr->version = odr_strdupn(o, buf + po, i - po);
     if (buf[i] != ' ')
     {
         o->error = OHTTP;
@@ -517,9 +507,9 @@ int yaz_decode_http_request(ODR o, Z_HTTP_Request **hr_p)
     Z_HTTP_Request *hr = (Z_HTTP_Request *) odr_malloc(o, sizeof(*hr));
     const char *buf = o->op->buf;
     int size = o->op->size;
+    int lspace = 0;
 
     *hr_p = hr;
-
     /* method .. */
     for (i = 0; buf[i] != ' '; i++)
         if (i >= size-5 || i > 30)
@@ -527,35 +517,22 @@ int yaz_decode_http_request(ODR o, Z_HTTP_Request **hr_p)
             o->error = OHTTP;
             return 0;
         }
-    hr->method = (char *) odr_malloc(o, i+1);
-    memcpy (hr->method, buf, i);
-    hr->method[i] = '\0';
-    /* path */
-    po = i+1;
-    for (i = po; buf[i] != ' '; i++)
-        if (i >= size-5)
-        {
-            o->error = OHTTP;
-            return 0;
-        }
-    hr->path = (char *) odr_malloc(o, i - po + 1);
-    memcpy (hr->path, buf+po, i - po);
-    hr->path[i - po] = '\0';
-    /* HTTP version */
-    i++;
-    if (i > size-5 || memcmp(buf+i, "HTTP/", 5))
+    hr->method = odr_strdupn(o, buf, i);
+    po = ++i;
+    while (i < size && !strchr("\r\n", buf[i]))
+    {
+        if (buf[i] == ' ')
+            lspace = i;
+        i++;
+    }
+    if (!lspace || i >= size || lspace >= size - 5 ||
+        memcmp(buf + lspace + 1, "HTTP/", 5))
     {
         o->error = OHTTP;
         return 0;
     }
-    i+= 5;
-    po = i;
-    while (i < size && !strchr("\r\n", buf[i]))
-        i++;
-    hr->version = (char *) odr_malloc(o, i - po + 1);
-    memcpy(hr->version, buf + po, i - po);
-    hr->version[i - po] = '\0';
-    /* headers */
+    hr->path = odr_strdupn(o, buf + po, lspace - po);
+    hr->version = odr_strdupn(o, buf + lspace + 6, i - (lspace + 6));
     if (i < size-1 && buf[i] == '\r')
         i++;
     if (buf[i] != '\n')
@@ -563,6 +540,7 @@ int yaz_decode_http_request(ODR o, Z_HTTP_Request **hr_p)
         o->error = OHTTP;
         return 0;
     }
+    /* headers */
     return decode_headers_content(o, i, &hr->headers,
                                   &hr->content_buf, &hr->content_len);
 }