Allowing free_action(NULL).
[privoxy.git] / parsers.c
index 9f70273..dbbeacf 100644 (file)
--- a/parsers.c
+++ b/parsers.c
@@ -1,4 +1,4 @@
-const char parsers_rcs[] = "$Id: parsers.c,v 1.38 2001/10/25 03:40:48 david__schmidt Exp $";
+const char parsers_rcs[] = "$Id: parsers.c,v 1.45 2002/01/09 14:33:03 oes Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/parsers.c,v $
@@ -10,8 +10,7 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.38 2001/10/25 03:40:48 david__sch
  *                   `client_uagent', `client_x_forwarded',
  *                   `client_x_forwarded_adder', `client_xtra_adder',
  *                   `content_type', `crumble', `destroy_list', `enlist',
- *                   `flush_socket', `free_http_request', `get_header',
- *                   `list_to_text', `parse_http_request', `sed',
+ *                   `flush_socket', ``get_header', `sed',
  *                   and `server_set_cookie'.
  *
  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
@@ -41,6 +40,30 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.38 2001/10/25 03:40:48 david__sch
  *
  * Revisions   :
  *    $Log: parsers.c,v $
+ *    Revision 1.45  2002/01/09 14:33:03  oes
+ *    Added support for localtime_r.
+ *
+ *    Revision 1.44  2001/12/14 01:22:54  steudten
+ *    Remove 'user:pass@' from 'proto://user:pass@host' for the
+ *    new added header 'Host: ..'. (See Req ID 491818)
+ *
+ *    Revision 1.43  2001/11/23 00:26:38  jongfoster
+ *    Fixing two really stupid errors in my previous commit
+ *
+ *    Revision 1.42  2001/11/22 21:59:30  jongfoster
+ *    Adding code to handle +no-cookies-keep
+ *
+ *    Revision 1.41  2001/11/05 23:43:05  steudten
+ *    Add time+date to log files.
+ *
+ *    Revision 1.40  2001/10/26 20:13:09  jongfoster
+ *    ctype.h is needed in Windows, too.
+ *
+ *    Revision 1.39  2001/10/26 17:40:04  oes
+ *    Introduced get_header_value()
+ *    Removed http->user_agent, csp->referrer and csp->accept_types
+ *    Removed client_accept()
+ *
  *    Revision 1.38  2001/10/25 03:40:48  david__schmidt
  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
  *    threads to call select() simultaneously.  So, it's time to do a real, live,
@@ -308,10 +331,10 @@ const char parsers_rcs[] = "$Id: parsers.c,v 1.38 2001/10/25 03:40:48 david__sch
 #ifndef _WIN32
 #include <stdio.h>
 #include <sys/types.h>
-#include <stdlib.h>
-#include <ctype.h>
 #endif
 
+#include <stdlib.h>
+#include <ctype.h>
 #include <assert.h>
 #include <string.h>
 
@@ -660,178 +683,6 @@ char *sed(const struct parsers pats[], void (* const more_headers[])(struct clie
 }
 
 
-/*********************************************************************
- *
- * Function    :  free_http_request
- *
- * Description :  Freez a http_request structure
- *
- * Parameters  :
- *          1  :  http = points to a http_request structure to free
- *
- * Returns     :  N/A
- *
- *********************************************************************/
-void free_http_request(struct http_request *http)
-{
-   assert(http);
-
-   freez(http->cmd);
-   freez(http->gpc);
-   freez(http->host);
-   freez(http->url);
-   freez(http->hostport);
-   freez(http->path);
-   freez(http->ver);
-   freez(http->host_ip_addr_str);
-
-}
-
-
-/*********************************************************************
- *
- * Function    :  parse_http_request
- *
- * Description :  Parse out the host and port from the URL.  Find the
- *                hostname & path, port (if ':'), and/or password (if '@')
- *
- * Parameters  :
- *          1  :  req = URL (or is it URI?) to break down
- *          2  :  http = pointer to the http structure to hold elements
- *          3  :  csp = Current client state (buffers, headers, etc...)
- *
- * Returns     :  N/A
- *
- *********************************************************************/
-void parse_http_request(char *req, struct http_request *http, struct client_state *csp)
-{
-   char *buf, *v[10], *url, *p;
-   int n;
-
-   memset(http, '\0', sizeof(*http));
-   http->cmd = strdup(req);
-
-   buf = strdup(req);
-   n = ssplit(buf, " \r\n", v, SZ(v), 1, 1);
-
-   if (n == 3)
-   {
-      /* this could be a CONNECT request */
-      if (strcmpic(v[0], "connect") == 0)
-      {
-         http->ssl      = 1;
-         http->gpc      = strdup(v[0]);
-         http->hostport = strdup(v[1]);
-         http->ver      = strdup(v[2]);
-      }
-
-      /* or it could be any other basic HTTP request type */
-      if ((0 == strcmpic(v[0], "get"))
-       || (0 == strcmpic(v[0], "head"))
-       || (0 == strcmpic(v[0], "post"))
-       || (0 == strcmpic(v[0], "put"))
-       || (0 == strcmpic(v[0], "delete"))
-
-       /* or a webDAV extension (RFC2518) */
-       || (0 == strcmpic(v[0], "propfind"))
-       || (0 == strcmpic(v[0], "proppatch"))
-       || (0 == strcmpic(v[0], "move"))
-       || (0 == strcmpic(v[0], "copy"))
-       || (0 == strcmpic(v[0], "mkcol"))
-       || (0 == strcmpic(v[0], "lock"))
-       || (0 == strcmpic(v[0], "unlock"))
-       )
-      {
-         http->ssl    = 0;
-         http->gpc    = strdup(v[0]);
-         http->url    = strdup(v[1]);
-         http->ver    = strdup(v[2]);
-
-         url = v[1];
-         if (strncmpic(url, "http://",  7) == 0)
-         {
-            url += 7;
-         }
-         else if (strncmpic(url, "https://", 8) == 0)
-         {
-            url += 8;
-         }
-         else
-         {
-            url = NULL;
-         }
-
-         if (url)
-         {
-            if ((p = strchr(url, '/')))
-            {
-               http->path = strdup(p);
-               *p = '\0';
-               http->hostport = strdup(url);
-            }
-            /*
-             * Repair broken HTTP requests that don't contain a path
-             */
-            else
-            {
-               http->path = strdup("/");
-               http->hostport = strdup(url);
-            }
-         }
-      }
-   }
-
-   freez(buf);
-
-
-   if (http->hostport == NULL)
-   {
-      free_http_request(http);
-      return;
-   }
-
-   buf = strdup(http->hostport);
-
-
-   /* check if url contains password */
-   n = ssplit(buf, "@", v, SZ(v), 1, 1);
-   if (n == 2)
-   {
-      char * newbuf = NULL;
-      newbuf = strdup(v[1]);
-      freez(buf);
-      buf = newbuf;
-   }
-
-   n = ssplit(buf, ":", v, SZ(v), 1, 1);
-
-   if (n == 1)
-   {
-      http->host = strdup(v[0]);
-      http->port = 80;
-   }
-
-   if (n == 2)
-   {
-      http->host = strdup(v[0]);
-      http->port = atoi(v[1]);
-   }
-
-   freez(buf);
-
-   if (http->host == NULL)
-   {
-      free_http_request(http);
-   }
-
-   if (http->path == NULL)
-   {
-      http->path = strdup("/");
-   }
-
-}
-
-
 /* here begins the family of parser functions that reformat header lines */
 
 
@@ -1399,11 +1250,22 @@ char *client_x_forwarded(const struct parsers *v, const char *s, struct client_s
  *********************************************************************/
 void client_host_adder(struct client_state *csp)
 {
-   char *p = NULL;
+   char *p = NULL,
+        *pos = NULL;
 
+   if ( !csp->http->hostport || !*(csp->http->hostport)) return;
    p = strsav(p, "Host: ");
-   p = strsav(p, csp->http->hostport);
-
+   /*
+   ** remove 'user:pass@' from 'proto://user:pass@host'
+   */
+   if ( (pos = strchr( csp->http->hostport, '@')) != NULL )
+   {
+       p = strsav(p, pos+1);
+   }
+   else
+   {
+      p = strsav(p, csp->http->hostport);
+   }
    log_error(LOG_LEVEL_HEADER, "addh: %s", p);
    enlist(csp->headers, p);
 
@@ -1639,7 +1501,24 @@ char *server_set_cookie(const struct parsers *v, const char *s, struct client_st
 #ifdef FEATURE_COOKIE_JAR
    if (csp->config->jar)
    {
-      fprintf(csp->config->jar, "%s\t%s\n", csp->http->host, (s + v->len + 1));
+      /*
+       * Write timestamp into outbuf.
+       *
+       * Complex because not all OSs have tm_gmtoff or
+       * the %z field in strftime()
+       */
+      char tempbuf[ BUFFER_SIZE ];
+      time_t now; 
+      struct tm tm_now; 
+      time (&now); 
+#ifdef HAVE_LOCALTIME_R
+       tm_now = *localtime_r(&now, &tm_now);
+#else
+       tm_now = *localtime (&now); 
+#endif
+      strftime(tempbuf, BUFFER_SIZE-6, "%b %d %H:%M:%S ", &tm_now); 
+
+      fprintf(csp->config->jar, "%s %s\t%s\n", tempbuf, csp->http->host, (s + v->len + 1));
    }
 #endif /* def FEATURE_COOKIE_JAR */
 
@@ -1647,9 +1526,86 @@ char *server_set_cookie(const struct parsers *v, const char *s, struct client_st
    {
       return(crumble(v, s, csp));
    }
+   else if ((csp->action->flags & ACTION_NO_COOKIE_KEEP) != 0)
+   {
+      /* Flag whether or not to log a message */
+      int changed = 0;
+
+      /* A variable to store the tag we're working on */
+      char * cur_tag;
+
+      /* Make a copy of the header we can write to */
+      char * result = strdup(s);
+      if (result == NULL)
+      {
+         /* FIXME: This error handling is incorrect */
+         return NULL;
+      }
+
+      /* Skip "Set-Cookie:" (11 characters) in header */
+      cur_tag = result + 11;
+
+      /* skip whitespace between "Set-Cookie:" and value */
+      while (*cur_tag && ijb_isspace(*cur_tag))
+      {
+         cur_tag++;
+      }
+
+      /* Loop through each tag in the cookie */
+      while (*cur_tag)
+      {
+         /* Find next tag */
+         char * next_tag = strchr(cur_tag, ';');
+         if (next_tag != NULL)
+         {
+            /* Skip the ';' character itself */
+            next_tag++;
+
+            /* skip whitespace ";" and start of tag */
+            while (*next_tag && ijb_isspace(*next_tag))
+            {
+               next_tag++;
+            }
+         }
+         else
+         {
+            /* "Next tag" is the end of the string */
+            next_tag = cur_tag + strlen(cur_tag);
+         }
+
+         /* Is this the "Expires" tag? */
+         if (strncmpic(cur_tag, "expires=", 8) == 0)
+         {
+            /* Delete the tag by copying the rest of the string over it.
+             * (Note that we cannot just use "strcpy(cur_tag, next_tag)",
+             * since the behaviour of strcpy is undefined for overlapping
+             * strings.)
+             */
+            memmove(cur_tag, next_tag, strlen(next_tag) + 1);
+
+            /* That changed the header, need to issue a log message */
+            changed = 1;
+
+            /* Note that the next tag has now been moved to *cur_tag,
+             * so we do not need to update the cur_tag pointer.
+             */
+         }
+         else
+         {
+            /* Move on to next cookie tag */
+            cur_tag = next_tag;
+         }
+      }
+
+      if (changed)
+      {
+         log_error(LOG_LEVEL_HEADER, "Changed cookie to a temporary one.");
+      }
+
+      return result;
+   }
 
    return(strdup(s));
-
 }