/[james]/httplint/httplint.c
ViewVC logotype

Diff of /httplint/httplint.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 42 by james, Wed Dec 17 18:45:44 2003 UTC revision 50 by james, Fri Feb 20 20:49:40 2004 UTC
# Line 1  Line 1 
1  /*  /*
2   * HTTP Header Lint   * HTTP Header Lint
3   * Licensed under the same license as Curl   * Licensed under the MIT License
4   *                http://curl.haxx.se/docs/copyright.html   *                http://www.opensource.org/licenses/mit-license
5   * Copyright 2003 James Bursa <bursa@users.sourceforge.net>   * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
6   */   */
7    
8  /*  /*
# Line 37  int status_code; Line 37  int status_code;
37  char error_buffer[CURL_ERROR_SIZE];  char error_buffer[CURL_ERROR_SIZE];
38  regex_t re_status_line, re_token, re_token_value, re_content_type, re_ugly,  regex_t re_status_line, re_token, re_token_value, re_content_type, re_ugly,
39      re_absolute_uri, re_etag, re_server, re_transfer_coding, re_upgrade,      re_absolute_uri, re_etag, re_server, re_transfer_coding, re_upgrade,
40      re_rfc1123, re_rfc1036, re_asctime;      re_rfc1123, re_rfc1036, re_asctime, re_cookie_nameval, re_cookie_expires;
41    
42    
43  void init(void);  void init(void);
# Line 81  void header_transfer_encoding_callback(c Line 81  void header_transfer_encoding_callback(c
81  void header_upgrade(const char *s);  void header_upgrade(const char *s);
82  void header_vary(const char *s);  void header_vary(const char *s);
83  void header_via(const char *s);  void header_via(const char *s);
84    void header_set_cookie(const char *s);
85  void die(const char *error);  void die(const char *error);
86  void warning(const char *message);  void warning(const char *message);
87  void error(const char *message);  void error(const char *message);
# Line 114  struct header_entry { Line 115  struct header_entry {
115    { "Pragma", header_pragma, 0, 0 },    { "Pragma", header_pragma, 0, 0 },
116    { "Retry-After", header_retry_after, 0, 0 },    { "Retry-After", header_retry_after, 0, 0 },
117    { "Server", header_server, 0, 0 },    { "Server", header_server, 0, 0 },
118      { "Set-Cookie", header_set_cookie, 0, 0 },
119    { "Trailer", header_trailer, 0, 0 },    { "Trailer", header_trailer, 0, 0 },
120    { "Transfer-Encoding", header_transfer_encoding, 0, 0 },    { "Transfer-Encoding", header_transfer_encoding, 0, 0 },
121    { "Upgrade", header_upgrade, 0, 0 },    { "Upgrade", header_upgrade, 0, 0 },
# Line 177  void init(void) Line 179  void init(void)
179        "^HTTP/([0-9]+)[.]([0-9]+) ([0-9][0-9][0-9]) ([\t -~€-ÿ]*)$",        "^HTTP/([0-9]+)[.]([0-9]+) ([0-9][0-9][0-9]) ([\t -~€-ÿ]*)$",
180        REG_EXTENDED);        REG_EXTENDED);
181    regcomp_wrapper(&re_token,    regcomp_wrapper(&re_token,
182        "^([-0-9a-zA-Z_.]+)",        "^([-0-9a-zA-Z_.!]+)",
183        REG_EXTENDED);        REG_EXTENDED);
184    regcomp_wrapper(&re_token_value,    regcomp_wrapper(&re_token_value,
185        "^([-0-9a-zA-Z_.]+)(=([-0-9a-zA-Z_.]+|\"([^\"]|[\\].)*\"))?",        "^([-0-9a-zA-Z_.!]+)(=([-0-9a-zA-Z_.!]+|\"([^\"]|[\\].)*\"))?",
186        REG_EXTENDED);        REG_EXTENDED);
187    regcomp_wrapper(&re_content_type,    regcomp_wrapper(&re_content_type,
188        "^([-0-9a-zA-Z_.]+)/([-0-9a-zA-Z_.]+)[ \t]*"        "^([-0-9a-zA-Z_.]+)/([-0-9a-zA-Z_.]+)[ \t]*"
# Line 194  void init(void) Line 196  void init(void)
196        "^(W/[ \t]*)?\"([^\"]|[\\].)*\"$",        "^(W/[ \t]*)?\"([^\"]|[\\].)*\"$",
197        REG_EXTENDED);        REG_EXTENDED);
198    regcomp_wrapper(&re_server,    regcomp_wrapper(&re_server,
199        "^((([-0-9a-zA-Z_.]+(/[-0-9a-zA-Z_.]+)?)|(\\(.*\\)))[ \t]*)+$",        "^((([-0-9a-zA-Z_.!]+(/[-0-9a-zA-Z_.]+)?)|(\\(.*\\)))[ \t]*)+$",
200        REG_EXTENDED);        REG_EXTENDED);
201    regcomp_wrapper(&re_transfer_coding,    regcomp_wrapper(&re_transfer_coding,
202        "^([-0-9a-zA-Z_.]+)[ \t]*"        "^([-0-9a-zA-Z_.]+)[ \t]*"
# Line 205  void init(void) Line 207  void init(void)
207        "^([-0-9a-zA-Z_.](/[-0-9a-zA-Z_.])?)+$",        "^([-0-9a-zA-Z_.](/[-0-9a-zA-Z_.])?)+$",
208        REG_EXTENDED);        REG_EXTENDED);
209    regcomp_wrapper(&re_ugly,    regcomp_wrapper(&re_ugly,
210        "^[a-zA-Z0-9]+://[^/]+[/a-zA-Z0-9-_]*$",        "^[a-zA-Z0-9]+://[^/]+[-/a-zA-Z0-9_]*$",
211        REG_EXTENDED);        REG_EXTENDED);
212    regcomp_wrapper(&re_rfc1123,    regcomp_wrapper(&re_rfc1123,
213        "^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), ([0123][0-9]) "        "^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), ([0123][0-9]) "
# Line 222  void init(void) Line 224  void init(void)
224        "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([ 12][0-9]) "        "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([ 12][0-9]) "
225        "([012][0-9]):([0-5][0-9]):([0-5][0-9]) ([0-9]{4})$",        "([012][0-9]):([0-5][0-9]):([0-5][0-9]) ([0-9]{4})$",
226        REG_EXTENDED);        REG_EXTENDED);
227      regcomp_wrapper(&re_cookie_nameval,
228          "^[^;, ]+=[^;, ]*$",
229          REG_EXTENDED);
230      regcomp_wrapper(&re_cookie_expires,
231          "^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), ([0123][0-9])-"
232          "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-([0-9]{4}) "
233          "([012][0-9]):([0-5][0-9]):([0-5][0-9]) GMT$",
234          REG_EXTENDED);
235  }  }
236    
237    
# Line 398  void check_header(const char *name, cons Line 408  void check_header(const char *name, cons
408    if (header) {    if (header) {
409      header->count++;      header->count++;
410      header->handler(value);      header->handler(value);
411    } else    } else if ((name[0] == 'X' || name[0] == 'x') && name[1] == '-') {
412        lookup("xheader");
413      } else {
414      lookup("nonstandard");      lookup("nonstandard");
415      }
416  }  }
417    
418    
# Line 817  void header_last_modified(const char *s) Line 830  void header_last_modified(const char *s)
830    time0 = time(0);    time0 = time(0);
831    if (!parse_date(s, &tm))    if (!parse_date(s, &tm))
832      return;      return;
833    time1 = mktime(&tm);    time1 = mktime_from_utc(&tm);
834    
835    diff = difftime(time1, time0);    diff = difftime(time1, time0);
836    if (10 < diff)    if (10 < diff)
# Line 938  void header_via(const char *s) Line 951  void header_via(const char *s)
951    lookup("via");    lookup("via");
952  }  }
953    
954    /* http://wp.netscape.com/newsref/std/cookie_spec.html */
955    void header_set_cookie(const char *s)
956    {
957      bool ok = true;
958      int r;
959      const char *semi = strchr(s, ';');
960      const char *s2;
961      struct tm tm;
962      double diff;
963      time_t time0, time1;
964      regmatch_t pmatch[20];
965    
966      if (semi)
967        s2 = strndup(s, semi - s);
968      else
969        s2 = s;
970    
971      r = regexec(&re_cookie_nameval, s2, 0, 0, 0);
972      if (r) {
973        lookup("cookiebadnameval");
974        ok = false;
975      }
976    
977      if (!semi)
978        return;
979    
980      s = skip_lws(semi + 1);
981    
982      while (*s) {
983        semi = strchr(s, ';');
984        if (semi)
985          s2 = strndup(s, semi - s);
986        else
987          s2 = s;
988    
989        if (strncmp(s2, "expires=", 8) == 0) {
990          s2 += 8;
991          r = regexec(&re_cookie_expires, s2, 20, pmatch, 0);
992          if (r == 0) {
993            tm.tm_mday = atoi(s2 + pmatch[2].rm_so);
994            tm.tm_mon = month(s2 + pmatch[3].rm_so);
995            tm.tm_year = atoi(s2 + pmatch[4].rm_so) - 1900;
996            tm.tm_hour = atoi(s2 + pmatch[5].rm_so);
997            tm.tm_min = atoi(s2 + pmatch[6].rm_so);
998            tm.tm_sec = atoi(s2 + pmatch[7].rm_so);
999    
1000            time0 = time(0);
1001            time1 = mktime_from_utc(&tm);
1002    
1003            diff = difftime(time0, time1);
1004            if (10 < diff) {
1005              lookup("cookiepastdate");
1006              ok = false;
1007            }
1008          } else {
1009            lookup("cookiebaddate");
1010            ok = false;
1011          }
1012        } else if (strncmp(s2, "domain=", 7) == 0) {
1013        } else if (strncmp(s2, "path=", 5) == 0) {
1014          if (s2[5] != '/') {
1015            lookup("cookiebadpath");
1016            ok = false;
1017          }
1018        } else if (strcmp(s, "secure") == 0) {
1019        } else {
1020          printf("    Set-Cookie field '%s':\n", s2);
1021          lookup("cookieunknownfield");
1022          ok = false;
1023        }
1024    
1025        if (semi)
1026          s = skip_lws(semi + 1);
1027        else
1028          break;
1029      }
1030    
1031      if (ok)
1032        lookup("ok");
1033    }
1034    
1035    
1036  /**  /**
1037   * Print an error message and exit.   * Print an error message and exit.
# Line 1042  struct message_entry { Line 1136  struct message_entry {
1136                    "of header names, or \"*\"." },                    "of header names, or \"*\"." },
1137    { "contentrange", "Warning: The Content-Range header should not be returned "    { "contentrange", "Warning: The Content-Range header should not be returned "
1138                      "by the server for this request." },                      "by the server for this request." },
1139      { "cookiebaddate", "Error: The expires date must be in the form "
1140                         "\"Wdy, DD-Mon-YYYY HH:MM:SS GMT\"." },
1141      { "cookiebadnameval", "Error: A Set-Cookie header must start with "
1142                            "name=value, each excluding semi-colon, comma and "
1143                            "white space." },
1144      { "cookiebadpath", "Error: The path does not start with \"/\"." },
1145      { "cookiepastdate", "Warning: The expires date is in the past. The cookie "
1146                          "will be deleted by browsers." },
1147      { "cookieunknownfield", "Warning: This is not a standard Set-Cookie "
1148                              "field." },
1149    { "futurehttp", "Warning: I only understand HTTP/1.1. Check for a newer "    { "futurehttp", "Warning: I only understand HTTP/1.1. Check for a newer "
1150                    "version of this tool." },                    "version of this tool." },
1151    { "futurelastmod", "Error: The specified Last-Modified date-time is in "    { "futurelastmod", "Error: The specified Last-Modified date-time is in "
# Line 1086  struct message_entry { Line 1190  struct message_entry {
1190    { "via", "This header was added by a proxy, cache or gateway." },    { "via", "This header was added by a proxy, cache or gateway." },
1191    { "wrongdate", "Warning: The server date-time differs from this system's "    { "wrongdate", "Warning: The server date-time differs from this system's "
1192                   "date-time by more than 10 seconds. Check that both the "                   "date-time by more than 10 seconds. Check that both the "
1193                   "system clocks are correct." }                   "system clocks are correct." },
1194      { "xheader", "This is an extension header. I don't know how to check it." }
1195  };  };
1196    
1197    

Legend:
Removed from v.42  
changed lines
  Added in v.50

  ViewVC Help
Powered by ViewVC 1.1.26