MARC-8: allow all characters 0x01-0x20 YAZ-650
[yaz-moved-to-github.git] / src / http.c
index 12e7c66..634f3c5 100644 (file)
@@ -1,26 +1,27 @@
-/*
- * Copyright (C) 1995-2007, Index Data ApS
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) 1995-2013 Index Data
  * See the file LICENSE for details.
- *
- * $Id: http.c,v 1.1 2007-01-11 10:55:57 adam Exp $
  */
-
 /**
  * \file http.c
  * \brief Implements HTTP decoding
  */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
 
-#include <ctype.h>
 #include <yaz/odr.h>
 #include <yaz/yaz-version.h>
 #include <yaz/yaz-iconv.h>
+#include <yaz/matchstr.h>
 #include <yaz/zgdu.h>
+#include <yaz/base64.h>
 
 #ifdef WIN32
 #define strncasecmp _strnicmp
 #define strcasecmp _stricmp
 #endif
+
 static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
                                   char **content_buf, int *content_len)
 {
@@ -58,11 +59,11 @@ static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
             i++;
         for (po = i; i < o->size-1 && !strchr("\r\n", o->buf[i]); i++)
             ;
-        
+
         (*headers)->value = (char*) odr_malloc(o, i - po + 1);
         memcpy ((*headers)->value, o->buf + po, i - po);
         (*headers)->value[i - po] = '\0';
-        
+
         if (!strcasecmp((*headers)->name, "Transfer-Encoding")
             &&
             !strcasecmp((*headers)->value, "chunked"))
@@ -82,23 +83,23 @@ static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
     if (chunked)
     {
         int off = 0;
-        
+
         /* we know buffer will be smaller than o->size - i*/
-        *content_buf = (char*) odr_malloc(o, o->size - i);  
-        
+        *content_buf = (char*) odr_malloc(o, o->size - i);
+
         while (1)
         {
             /* chunk length .. */
             int chunk_len = 0;
             for (; i  < o->size-2; i++)
-                if (isdigit(o->buf[i]))
-                    chunk_len = chunk_len * 16 + 
+                if (yaz_isdigit(o->buf[i]))
+                    chunk_len = chunk_len * 16 +
                         (o->buf[i] - '0');
-                else if (isupper(o->buf[i]))
-                    chunk_len = chunk_len * 16 + 
+                else if (yaz_isupper(o->buf[i]))
+                    chunk_len = chunk_len * 16 +
                         (o->buf[i] - ('A'-10));
-                else if (islower(o->buf[i]))
-                    chunk_len = chunk_len * 16 + 
+                else if (yaz_islower(o->buf[i]))
+                    chunk_len = chunk_len * 16 +
                         (o->buf[i] - ('a'-10));
                 else
                     break;
@@ -141,7 +142,7 @@ static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
             *content_buf = 0;
             *content_len = 0;
         }
-        else 
+        else
         {
             *content_len = o->size - i;
             *content_buf = (char*) odr_malloc(o, *content_len + 1);
@@ -159,7 +160,8 @@ void z_HTTP_header_add_content_type(ODR o, Z_HTTP_Header **hp,
     const char *l = "Content-Type";
     if (charset)
     {
-        char *ctype = odr_malloc(o, strlen(content_type)+strlen(charset) + 15);
+        char *ctype = (char *)
+            odr_malloc(o, strlen(content_type)+strlen(charset) + 15);
         sprintf(ctype, "%s; charset=%s", content_type, charset);
         z_HTTP_header_add(o, hp, l, ctype);
     }
@@ -168,6 +170,31 @@ void z_HTTP_header_add_content_type(ODR o, Z_HTTP_Header **hp,
 
 }
 
+/*
+ * HTTP Basic authentication is described at:
+ * http://tools.ietf.org/html/rfc1945#section-11.1
+ */
+void z_HTTP_header_add_basic_auth(ODR o, Z_HTTP_Header **hp,
+                                  const char *username, const char *password)
+{
+    char *tmp, *buf;
+    int len;
+
+    if (username == 0)
+        return;
+    if (password == 0)
+        password = "";
+
+    len = strlen(username) + strlen(password);
+    tmp = (char *) odr_malloc(o, len+2);
+    sprintf(tmp, "%s:%s", username, password);
+    buf = (char *) odr_malloc(o, (len+1) * 8/6 + 12);
+    strcpy(buf, "Basic ");
+    yaz_base64encode(tmp, &buf[strlen(buf)]);
+    z_HTTP_header_add(o, hp, "Authorization", buf);
+}
+
+
 void z_HTTP_header_add(ODR o, Z_HTTP_Header **hp, const char *n,
                        const char *v)
 {
@@ -240,6 +267,48 @@ Z_GDU *z_get_HTTP_Request_host_path(ODR odr,
     return p;
 }
 
+Z_GDU *z_get_HTTP_Request_uri(ODR odr, const char *uri, const char *args,
+                              int use_full_uri)
+{
+    Z_GDU *p = z_get_HTTP_Request(odr);
+    const char *cp0 = strstr(uri, "://");
+    const char *cp1 = 0;
+    if (cp0)
+        cp0 = cp0+3;
+    else
+        cp0 = uri;
+
+    cp1 = strchr(cp0, '/');
+    if (!cp1)
+        cp1 = cp0+strlen(cp0);
+
+    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);
+    }
+
+    if (!args)
+    {
+        if (*cp1)
+            args = cp1 + 1;
+        else
+            args = "";
+    }
+    p->u.HTTP_Request->path = odr_malloc(odr, cp1 - uri + strlen(args) + 2);
+    if (use_full_uri)
+    {
+        memcpy(p->u.HTTP_Request->path, uri, cp1 - uri);
+        strcpy(p->u.HTTP_Request->path + (cp1 - uri), "/");
+    }
+    else
+        strcpy(p->u.HTTP_Request->path, "/");
+    strcat(p->u.HTTP_Request->path, args);
+    return p;
+}
 
 Z_GDU *z_get_HTTP_Response(ODR o, int code)
 {
@@ -259,20 +328,21 @@ Z_GDU *z_get_HTTP_Response(ODR o, int code)
     if (code != 200)
     {
         hres->content_buf = (char*) odr_malloc(o, 400);
-        sprintf (hres->content_buf, 
-                 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
-                 "<HTML>\n"
-                 " <HEAD>\n"
-                 "  <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
-                 " </HEAD>\n"
-                 " <BODY>\n"
-                 "  <P><A HREF=\"http://www.indexdata.dk/yaz/\">YAZ</A> " 
-                 YAZ_VERSION "</P>\n"
-                 "  <P>Error: %d</P>\n"
-                 "  <P>Description: %.50s</P>\n"
-                 " </BODY>\n"
-                 "</HTML>\n",
-                 code, z_HTTP_errmsg(code));
+        sprintf(hres->content_buf,
+                "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""
+                " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
+                "<HTML>\n"
+                " <HEAD>\n"
+                "  <TITLE>YAZ " YAZ_VERSION "</TITLE>\n"
+                " </HEAD>\n"
+                " <BODY>\n"
+                "  <P><A HREF=\"http://www.indexdata.com/yaz/\">YAZ</A> "
+                YAZ_VERSION "</P>\n"
+                "  <P>Error: %d</P>\n"
+                "  <P>Description: %.50s</P>\n"
+                " </BODY>\n"
+                "</HTML>\n",
+                code, z_HTTP_errmsg(code));
         hres->content_len = strlen(hres->content_buf);
         z_HTTP_header_add(o, &hres->headers, "Content-Type", "text/html");
     }
@@ -299,11 +369,11 @@ int yaz_decode_http_response(ODR o, Z_HTTP_Response **hr_p)
 {
     int i, po;
     Z_HTTP_Response *hr = (Z_HTTP_Response *) odr_malloc(o, sizeof(*hr));
-    
+
     *hr_p = hr;
     hr->content_buf = 0;
     hr->content_len = 0;
-    
+
     po = i = 5;
     while (i < o->size-2 && !strchr(" \r\n", o->buf[i]))
         i++;
@@ -326,16 +396,16 @@ int yaz_decode_http_response(ODR o, Z_HTTP_Response **hr_p)
     while (i < o->size-1 && o->buf[i] != '\n')
         i++;
     return decode_headers_content(o, i, &hr->headers,
-                                  &hr->content_buf, &hr->content_len);            
+                                  &hr->content_buf, &hr->content_len);
 }
 
 int yaz_decode_http_request(ODR o, Z_HTTP_Request **hr_p)
 {
     int i, po;
     Z_HTTP_Request *hr = (Z_HTTP_Request *) odr_malloc(o, sizeof(*hr));
-    
+
     *hr_p = hr;
-    
+
     /* method .. */
     for (i = 0; o->buf[i] != ' '; i++)
         if (i >= o->size-5 || i > 30)
@@ -411,7 +481,7 @@ int yaz_encode_http_response(ODR o, Z_HTTP_Response *hr)
     }
     odr_write(o, (unsigned char *) "\r\n", 2);
     if (hr->content_buf)
-        odr_write(o, (unsigned char *) 
+        odr_write(o, (unsigned char *)
                   hr->content_buf,
                   hr->content_len);
     if (o->direction == ODR_PRINT)
@@ -470,6 +540,7 @@ int yaz_encode_http_request(ODR o, Z_HTTP_Request *hr)
 /*
  * Local variables:
  * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
  * indent-tabs-mode: nil
  * End:
  * vim: shiftwidth=4 tabstop=8 expandtab