wsp_headers.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:84k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * wsp_headers.c - Implement WSP PDU headers
  3.  * 
  4.  * References:
  5.  *   WSP specification version 1.1
  6.  *   RFC 2068, Hypertext Transfer Protocol HTTP/1.1
  7.  *   RFC 2616, Hypertext Transfer Protocol HTTP/1.1
  8.  *
  9.  *   For push headers, WSP specification, June 2000 conformance release
  10.  *
  11.  * This file has two parts.  The first part decodes the request's headers
  12.  * from WSP to HTTP.  The second part encodes the response's headers from
  13.  * HTTP to WSP.
  14.  *
  15.  * Note that push header encoding and decoding are divided two parts:
  16.  * first decoding and encoding numeric values and then packing these values
  17.  * into WSP format and unpacking them from WSP format. This module contains
  18.  * only packing and unpacking parts.
  19.  *
  20.  * Richard Braakman
  21.  */
  22. #include <string.h>
  23. #include <limits.h>
  24. #include <ctype.h>
  25. #include "gwlib/gwlib.h"
  26. #include "wsp.h"
  27. #include "wsp_headers.h"
  28. #include "wsp_strings.h"
  29. #define WSP_FIELD_VALUE_NUL_STRING 1
  30. #define WSP_FIELD_VALUE_ENCODED  2
  31. #define WSP_FIELD_VALUE_DATA 3
  32. #define WSP_FIELD_VALUE_NONE 4 /* secondary_field_value only */
  33. /* The value defined as Quote in 8.4.2.1 */
  34. #define WSP_QUOTE  127
  35. /* Largest value that will fit in a Short-integer encoding */
  36. #define MAX_SHORT_INTEGER 127
  37. /* Marker values used in the encoding */
  38. #define BASIC_AUTHENTICATION 128
  39. #define ABSOLUTE_TIME 128
  40. #define RELATIVE_TIME 129
  41. #define BYTE_RANGE 128
  42. #define SUFFIX_BYTE_RANGE 129
  43. /* Use this value for Expires headers if we can't parse the expiration
  44.  * date.  It's about one day after the start of the epoch.  We don't
  45.  * use the exact start of the epoch because some clients have trouble
  46.  * with that. */
  47. #define LONG_AGO_VALUE 100000
  48. /*
  49.  * get field value and return its type as predefined data types
  50.  * There are three kinds of field encodings:
  51.  *   WSP_FIELD_VALUE_NUL_STRING: 0-terminated string
  52.  *   WSP_FIELD_VALUE_ENCODED: short integer, range 0-127
  53.  *   WSP_FIELD_VALUE_DATA: octet string defined by length
  54.  * The function will return one of those values, and modify the parse context
  55.  * to make it easy to get the field data.
  56.  *   WSP_FIELD_VALUE_NUL_STRING: Leave parsing position at start of string
  57.  *   WSP_FIELD_VALUE_ENCODED: Put value in *well_known_value, leave
  58.  *        parsing position after field value.
  59.  *   WSP_FIELD_VALUE_DATA: Leave parsing position at start of data, and set
  60.  *        a parse limit at the end of data.
  61.  */
  62. static int field_value(ParseContext *context, int *well_known_value)
  63. {
  64.     int val;
  65.     unsigned long len;
  66.     val = parse_get_char(context);
  67.     if (val >= 0 && val < 31) {
  68.         *well_known_value = -1;
  69.         parse_limit(context, val);
  70.         return WSP_FIELD_VALUE_DATA;
  71.     } else if (val == 31) {
  72.         *well_known_value = -1;
  73.         len = parse_get_uintvar(context);
  74.         parse_limit(context, len);
  75.         return WSP_FIELD_VALUE_DATA;
  76.     } else if (val > 127) {
  77.         *well_known_value = val - 128;
  78.         return WSP_FIELD_VALUE_ENCODED;
  79.     } else if (val == WSP_QUOTE) {  /* 127 */
  80.         *well_known_value = -1;
  81.         /* We already consumed the Quote */
  82.         return WSP_FIELD_VALUE_NUL_STRING;
  83.     } else {
  84.         *well_known_value = -1;
  85.         /* Un-parse the character we just read */
  86.         parse_skip(context, -1);
  87.         return WSP_FIELD_VALUE_NUL_STRING;
  88.     }
  89. }
  90. /* Skip over a field_value as defined above. */
  91. static void skip_field_value(ParseContext *context)
  92. {
  93.     int val;
  94.     int ret;
  95.     ret = field_value(context, &val);
  96.     if (ret == WSP_FIELD_VALUE_DATA) {
  97.         parse_skip_to_limit(context);
  98.         parse_pop_limit(context);
  99.     }
  100. }
  101. /* Multi-octet-integer is defined in 8.4.2.1 */
  102. static long unpack_multi_octet_integer(ParseContext *context, long len)
  103. {
  104.     long val = 0;
  105.     if (len > (long) sizeof(val) || len < 0)
  106.         return -1;
  107.     while (len > 0) {
  108.         val = val * 256 + parse_get_char(context);
  109.         len--;
  110.     }
  111.     if (parse_error(context))
  112.         return -1;
  113.     return val;
  114. }
  115. /* This function is similar to field_value, but it is used at various
  116.  * places in the grammar where we expect either an Integer-value
  117.  * or some kind of NUL-terminated text.
  118.  * 
  119.  * Return values are just like field_value except that WSP_FIELD_VALUE_DATA
  120.  * will not be returned.
  121.  *
  122.  * As a special case, we parse a 0-length Long-integer as an
  123.  * WSP_FIELD_VALUE_NONE, so that we can distinguish between No-value
  124.  * and an Integer-value of 0.  (A real integer 0 would be encoded as
  125.  * a Short-integer; the definition of Long-integer seems to allow
  126.  * 0-length integers, but the definition of Multi-octet-integer does
  127.  * not, so this is an unclear area of the specification.)
  128.  */
  129. static int secondary_field_value(ParseContext *context, long *result)
  130. {
  131.     int val;
  132.     long length;
  133.     val = parse_get_char(context);
  134.     if (val == 0) {
  135.         *result = 0;
  136.         return WSP_FIELD_VALUE_NONE;
  137.     } else if (val > 0 && val < 31) {
  138.         *result = unpack_multi_octet_integer(context, val);
  139.         return WSP_FIELD_VALUE_ENCODED;
  140.     } else if (val == 31) {
  141.         length = parse_get_uintvar(context);
  142.         *result = unpack_multi_octet_integer(context, length);
  143.         return WSP_FIELD_VALUE_ENCODED;
  144.     } else if (val > 127) {
  145.         *result = val - 128;
  146.         return WSP_FIELD_VALUE_ENCODED;
  147.     } else if (val == WSP_QUOTE) {  /* 127 */
  148.         *result = -1;
  149.         return WSP_FIELD_VALUE_NUL_STRING;
  150.     } else {
  151.         *result = -1;
  152.         /* Un-parse the character we just read */
  153.         parse_skip(context, -1);
  154.         return WSP_FIELD_VALUE_NUL_STRING;
  155.     }
  156. }
  157. /* Integer-value is defined in 8.4.2.3 */
  158. static Octstr *unpack_integer_value(ParseContext *context)
  159. {
  160.     Octstr *decoded;
  161.     unsigned long value;
  162.     int val;
  163.     val = parse_get_char(context);
  164.     if (val < 31) {
  165.         value = unpack_multi_octet_integer(context, val);
  166.     } else if (val > 127) {
  167.         value = val - 128;
  168.     } else {
  169.         warning(0, "WSP headers: bad integer-value.");
  170.         return NULL;
  171.     }
  172.     decoded = octstr_create("");
  173.     octstr_append_decimal(decoded, value);
  174.     return decoded;
  175. }
  176. /* Q-value is defined in 8.4.2.3 */
  177. static Octstr *convert_q_value(int q)
  178. {
  179.     Octstr *result = NULL;
  180.     /* When quality factor 0 and quality factors with one or two
  181.      * decimal digits are encoded, they shall be multiplied by 100
  182.      * and incremented by one, so that they encode as a one-octet
  183.      * value in range 1-100. */
  184.     if (q >= 1 && q <= 100) {
  185.         q = q - 1;
  186.         result = octstr_create("0.");
  187.         octstr_append_char(result, (q / 10) + '0');
  188.         if (q % 10 > 0)
  189.             octstr_append_char(result, (q % 10) + '0');
  190.         return result;
  191.     }
  192.     /* Three decimal quality factors shall be multiplied with 1000
  193.      * and incremented by 100. */
  194.     if (q > 100 && q <= 1000) {
  195.         q = q - 100;
  196.         result = octstr_create("0.");
  197.         octstr_append_char(result, (q / 100) + '0');
  198.         if (q % 100 > 0)
  199.             octstr_append_char(result, (q / 10 % 10) + '0');
  200.         if (q % 10 > 0)
  201.             octstr_append_char(result, (q % 10) + '0');
  202.         return result;
  203.     }
  204.     return NULL;
  205. }
  206. /* Q-value is defined in 8.4.2.3 */
  207. static Octstr *unpack_q_value(ParseContext *context)
  208. {
  209.     int c, c2;
  210.     c = parse_get_char(context);
  211.     if (c < 0)
  212.         return NULL;
  213.     if (c & 0x80) {
  214.         c2 = parse_get_char(context);
  215.         if (c2 < 0 || (c2 & 0x80))
  216.             return NULL;
  217.         c = ((c & 0x7f) << 8) + c2;
  218.     }
  219.     return convert_q_value(c);
  220. }
  221. /* Version-value is defined in 8.4.2.3 */
  222. static Octstr *unpack_version_value(long value)
  223. {
  224.     Octstr *result;
  225.     int major, minor;
  226.     major = ((value >> 4) & 0x7);
  227.     minor = (value & 0xf);
  228.     result = octstr_create("");
  229.     octstr_append_char(result, major + '0');
  230.     if (minor != 15) {
  231.         octstr_append_char(result, '.');
  232.         octstr_append_decimal(result, minor);
  233.     }
  234.     return result;
  235. }
  236. /* Called with the parse limit set to the end of the parameter data,
  237.  * and decoded containing the unpacked header line so far.
  238.  * Parameter is defined in 8.4.2.4. */
  239. static int unpack_parameter(ParseContext *context, Octstr *decoded)
  240. {
  241.     Octstr *parm = NULL;
  242.     Octstr *value = NULL;
  243.     int ret;
  244.     long type;
  245.     long val;
  246.     ret = secondary_field_value(context, &type);
  247.     if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
  248.         warning(0, "bad parameter");
  249.         goto error;
  250.     }
  251.     if (ret == WSP_FIELD_VALUE_ENCODED) {
  252.         /* Typed-parameter */
  253.         parm = wsp_parameter_to_string(type);
  254.         if (!parm)
  255.             warning(0, "Unknown parameter %02lx.", type);
  256.     } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
  257.         /* Untyped-parameter */
  258.         parm = parse_get_nul_string(context);
  259.         if (!parm)
  260.             warning(0, "Format error in parameter.");
  261.         type = -1;
  262.         /* We treat Untyped-value as a special type.  Its format
  263.          * Integer-value | Text-value is pretty similar to most
  264.          * typed formats. */
  265.     } else {
  266.         panic(0, "Unknown secondary field value type %d.", ret);
  267.     }
  268.     if (type == 0x00) /* q */
  269.         value = unpack_q_value(context);
  270.     else {
  271.         ret = secondary_field_value(context, &val);
  272.         if (parse_error(context)) {
  273.             warning(0, "bad parameter value");
  274.             goto error;
  275.         }
  276.         if (ret == WSP_FIELD_VALUE_ENCODED) {
  277.             switch (type) {
  278.             case -1:  /* untyped: Integer-value */
  279.             case 3:  /* type: Integer-value */
  280.             case 8:  /* padding: Short-integer */
  281.                 value = octstr_create("");
  282.                 octstr_append_decimal(value, val);
  283.                 break;
  284.             case 0:  /* q, already handled above */
  285.                 gw_assert(0);
  286.                 break;
  287.             case 1:  /* charset: Well-known-charset */
  288.                 value = wsp_charset_to_string(val);
  289.                 if (!value)
  290.                     warning(0, "Unknown charset %04lx.", val);
  291.                 break;
  292.             case 2:  /* level: Version-value */
  293.                 value = unpack_version_value(val);
  294.                 break;
  295.             case 5:  /* name: Text-string */
  296.             case 6:  /* filename: Text-string */
  297.                 warning(0, "Text-string parameter with integer encoding");
  298.                 break;
  299.             case 7:  /* differences: Field-name */
  300.                 value = wsp_header_to_string(val);
  301.                 if (!value)
  302.                     warning(0, "Unknown differences header %02lx.", val);
  303.                 break;
  304.             default:
  305.                 warning(0, "Unknown parameter encoding %02lx.",
  306.                         type);
  307.                 break;
  308.             }
  309.         } else if (ret == WSP_FIELD_VALUE_NONE) {
  310.             value = octstr_create("");
  311.         } else {
  312.             gw_assert(ret == WSP_FIELD_VALUE_NUL_STRING);
  313.             /* Text-value = No-value | Token-text | Quoted-string */
  314.             value = parse_get_nul_string(context);
  315.             if (!value)
  316.                 warning(0, "Format error in parameter value.");
  317.             else {
  318.                 if (octstr_get_char(value, 0) == '"') {
  319.                     /* Quoted-string */
  320.                     octstr_append_char(value, '"');
  321.                 }
  322.             }
  323.         }
  324.     }
  325.     if (!parm || !value) {
  326.         warning(0, "Skipping parameters");
  327.         goto error;
  328.     }
  329.     octstr_append(decoded, octstr_imm("; "));
  330.     octstr_append(decoded, parm);
  331.     if (octstr_len(value) > 0) {
  332.         octstr_append_char(decoded, '=');
  333.         octstr_append(decoded, value);
  334.     }
  335.     octstr_destroy(parm);
  336.     octstr_destroy(value);
  337.     return 0;
  338. error:
  339.     parse_skip_to_limit(context);
  340.     octstr_destroy(parm);
  341.     octstr_destroy(value);
  342.     parse_set_error(context);
  343.     return -1;
  344. }
  345. static void unpack_all_parameters(ParseContext *context, Octstr *decoded)
  346. {
  347.     int ret = 0;
  348.     while (ret >= 0 && !parse_error(context) &&
  349.            parse_octets_left(context) > 0) {
  350.         ret = unpack_parameter(context, decoded);
  351.     }
  352. }
  353. /* Unpack parameters in the format used by credentials and challenge,
  354.  * which differs from the format used by all other HTTP headers. */
  355. static void unpack_broken_parameters(ParseContext *context, Octstr *decoded)
  356. {
  357.     int ret = 0;
  358.     int first = 1;
  359.     long pos;
  360.     while (ret >= 0 && !parse_error(context) &&
  361.    parse_octets_left(context) > 0) {
  362.         pos = octstr_len(decoded);
  363.         ret = unpack_parameter(context, decoded);
  364.         if (ret >= 0) {
  365.             if (first) {
  366.                 /* Zap ';' */
  367.                 octstr_delete(decoded, pos, 1);
  368.                 first = 0;
  369.             } else {
  370.                 /* Replace ';' with ',' */
  371.                 octstr_set_char(decoded, pos, first ? ' ' : ',');
  372.             }
  373.         }
  374.     }
  375. }
  376. static void unpack_optional_q_value(ParseContext *context, Octstr *decoded)
  377. {
  378.     if (parse_octets_left(context) > 0) {
  379.         Octstr *qval = unpack_q_value(context);
  380.         if (qval) {
  381.             octstr_append(decoded, octstr_imm("; q="));
  382.             octstr_append(decoded, qval);
  383.             octstr_destroy(qval);
  384.         } else
  385.             warning(0, "Bad q-value");
  386.     }
  387. }
  388. /* Date-value is defined in 8.4.2.3. */
  389. static Octstr *unpack_date_value(ParseContext *context)
  390. {
  391.     unsigned long timeval;
  392.     int length;
  393.     length = parse_get_char(context);
  394.     if (length > 30) {
  395.         warning(0, "WSP headers: bad date-value.");
  396.         return NULL;
  397.     }
  398.     timeval = unpack_multi_octet_integer(context, length);
  399.     if (timeval < 0) {
  400.         warning(0, "WSP headers: cannot unpack date-value.");
  401.         return NULL;
  402.     }
  403.     return date_format_http(timeval);
  404. }
  405. /* Accept-general-form is defined in 8.4.2.7 */
  406. static Octstr *unpack_accept_general_form(ParseContext *context)
  407. {
  408.     Octstr *decoded = NULL;
  409.     int ret;
  410.     long val;
  411.     /* The definition for Accept-general-form looks quite complicated,
  412.      * but the "Q-token Q-value" part fits the normal expansion of
  413.      * Parameter, so it simplifies to:
  414.      *  Value-length Media-range *(Parameter)
  415.      * and we've already parsed Value-length.
  416.      */
  417.     /* We use this function to parse content-general-form too,
  418.      * because its definition of Media-type is identical to Media-range.
  419.      */
  420.     ret = secondary_field_value(context, &val);
  421.     if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
  422.         warning(0, "bad media-range or media-type");
  423.         return NULL;
  424.     }
  425.     if (ret == WSP_FIELD_VALUE_ENCODED) {
  426.         decoded = wsp_content_type_to_string(val);
  427.         if (!decoded) {
  428.             warning(0, "Unknown content type 0x%02lx.", val);
  429.             return NULL;
  430.         }
  431.     } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
  432.         decoded = parse_get_nul_string(context);
  433.         if (!decoded) {
  434.             warning(0, "Format error in content type");
  435.             return NULL;
  436.         }
  437.     } else {
  438.         panic(0, "Unknown secondary field value type %d.", ret);
  439.     }
  440.     unpack_all_parameters(context, decoded);
  441.     return decoded;
  442. }
  443. /* Accept-charset-general-form is defined in 8.4.2.8 */
  444. static Octstr *unpack_accept_charset_general_form(ParseContext *context)
  445. {
  446.     Octstr *decoded = NULL;
  447.     int ret;
  448.     long val;
  449.     ret = secondary_field_value(context, &val);
  450.     if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
  451.         warning(0, "Bad accept-charset-general-form");
  452.         return NULL;
  453.     }
  454.     if (ret == WSP_FIELD_VALUE_ENCODED) {
  455.         decoded = wsp_charset_to_string(val);
  456.         if (!decoded) {
  457.             warning(0, "Unknown character set %04lx.", val);
  458.             return NULL;
  459.         }
  460.     } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
  461.         decoded = parse_get_nul_string(context);
  462.         if (!decoded) {
  463.             warning(0, "Format error in accept-charset");
  464.             return NULL;
  465.         }
  466.     } else {
  467.         panic(0, "Unknown secondary field value type %d.", ret);
  468.     }
  469.     unpack_optional_q_value(context, decoded);
  470.     return decoded;
  471. }
  472. /* Accept-language-general-form is defined in 8.4.2.10 */
  473. static Octstr *unpack_accept_language_general_form(ParseContext *context)
  474. {
  475.     Octstr *decoded = NULL;
  476.     int ret;
  477.     long val;
  478.     ret = secondary_field_value(context, &val);
  479.     if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
  480.         warning(0, "Bad accept-language-general-form");
  481.         return NULL;
  482.     }
  483.     if (ret == WSP_FIELD_VALUE_ENCODED) {
  484.         /* Any-language is handled by a special entry in the
  485.          * language table. */
  486.         decoded = wsp_language_to_string(val);
  487.         if (!decoded) {
  488.             warning(0, "Unknown language %02lx.", val);
  489.             return NULL;
  490.         }
  491.     } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
  492.         decoded = parse_get_nul_string(context);
  493.         if (!decoded) {
  494.             warning(0, "Format error in accept-language");
  495.             return NULL;
  496.         }
  497.     } else {
  498.         panic(0, "Unknown secondary field value type %d.", ret);
  499.     }
  500.     unpack_optional_q_value(context, decoded);
  501.     return decoded;
  502. }
  503. /* Credentials is defined in 8.4.2.5 */
  504. static Octstr *unpack_credentials(ParseContext *context)
  505. {
  506.     Octstr *decoded = NULL;
  507.     int val;
  508.     val = parse_peek_char(context);
  509.     if (val == BASIC_AUTHENTICATION) {
  510.         Octstr *userid, *password;
  511.         parse_skip(context, 1);
  512.         userid = parse_get_nul_string(context);
  513.         password = parse_get_nul_string(context);
  514.         if (parse_error(context)) {
  515.             octstr_destroy(userid);
  516.             octstr_destroy(password);
  517.         } else {
  518.             /* Create the user-pass cookie */
  519.             decoded = octstr_duplicate(userid);
  520.             octstr_append_char(decoded, ':');
  521.             octstr_append(decoded, password);
  522.             /* XXX Deal with cookies that overflow the 76-per-line
  523.              * limit of base64.  Either go through and zap all
  524.              * CR LF sequences, or give the conversion function
  525.              * a flag or something to leave them out. */
  526.             octstr_binary_to_base64(decoded);
  527.             /* Zap the CR LF at the end */
  528.             octstr_delete(decoded, octstr_len(decoded) - 2, 2);
  529.             octstr_insert_data(decoded, 0, "Basic ", 6);
  530.             octstr_destroy(userid);
  531.             octstr_destroy(password);
  532.         }
  533.     } else if (val >= 32 && val < 128) {
  534.         /* Generic authentication scheme */
  535.         decoded = parse_get_nul_string(context);
  536.         if (decoded)
  537.             unpack_broken_parameters(context, decoded);
  538.     }
  539.     if (!decoded)
  540.         warning(0, "Cannot parse credentials.");
  541.     return decoded;
  542. }
  543. /* Challenge is defined in 8.4.2.5 */
  544. static Octstr *unpack_challenge(ParseContext *context)
  545. {
  546.     Octstr *decoded = NULL;
  547.     Octstr *realm_value = NULL;
  548.     int val;
  549.     val = parse_peek_char(context);
  550.     if (val == BASIC_AUTHENTICATION) {
  551.         parse_skip(context, 1);
  552.         realm_value = parse_get_nul_string(context);
  553.         if (realm_value) {
  554.             decoded = octstr_create("Basic realm="");
  555.             octstr_append(decoded, realm_value);
  556.             octstr_append_char(decoded, '"');
  557.         }
  558.     } else if (val >= 32 && val < 128) {
  559.         /* Generic authentication scheme */
  560.         decoded = parse_get_nul_string(context);
  561.         realm_value = parse_get_nul_string(context);
  562.         if (decoded && realm_value) {
  563.             octstr_append(decoded,
  564.                           octstr_imm(" realm=""));
  565.             octstr_append(decoded, realm_value);
  566.             octstr_append_char(decoded, '"');
  567.             if (parse_octets_left(context) > 0) {
  568.                 /* Prepare for following parameter list */
  569.                 octstr_append_char(decoded, ',');
  570.             }
  571.             unpack_broken_parameters(context, decoded);
  572.         }
  573.     }
  574.     if (!decoded)
  575.         warning(0, "Cannot parse challenge.");
  576.     octstr_destroy(realm_value);
  577.     return decoded;
  578. }
  579. /* Content-range is defined in 8.4.2.23 */
  580. static Octstr *unpack_content_range(ParseContext *context)
  581. {
  582.     /* We'd have to figure out how to access the content range
  583.      * length (i.e. user_data size) from here to parse this,
  584.      * and I don't see why the _client_ would send this in any case. */
  585.     warning(0, "Decoding of content-range not supported");
  586.     return NULL;
  587.     /*
  588.      Octstr *decoded = NULL;
  589.      unsigned long first_byte_pos, entity_length;
  590.      unsigned long last_byte_pos;
  591.      
  592.      first_byte_pos = parse_get_uintvar(context);
  593.      entity_length = parse_get_uintvar(context);
  594.      
  595.      if (parse_error(context)) {
  596.      warning(0, "Cannot parse content-range header");
  597.      return NULL;
  598.      }
  599.      
  600.      decoded = octstr_create("bytes ");
  601.      octstr_append_decimal(decoded, first_byte_pos);
  602.      octstr_append_char(decoded, '-');
  603.      octstr_append_decimal(decoded, last_byte_pos);
  604.      octstr_append_char(decoded, '/');
  605.      octstr_append_decimal(decoded, entity_length);
  606.      
  607.      return decoded;
  608.     */
  609. }
  610. /* Field-name is defined in 8.4.2.6 */
  611. static Octstr *unpack_field_name(ParseContext *context)
  612. {
  613.     Octstr *decoded = NULL;
  614.     int ret;
  615.     int val;
  616.     ret = field_value(context, &val);
  617.     if (parse_error(context) || ret == WSP_FIELD_VALUE_DATA) {
  618.         warning(0, "Bad field-name encoding");
  619.         return NULL;
  620.     }
  621.     if (ret == WSP_FIELD_VALUE_ENCODED) {
  622.         decoded = wsp_header_to_string(val);
  623.         if (!decoded) {
  624.             warning(0, "Unknown field-name 0x%02x.", val);
  625.             return NULL;
  626.         }
  627.     } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
  628.         decoded = parse_get_nul_string(context);
  629.         if (!decoded) {
  630.             warning(0, "Bad field-name encoding");
  631.             return NULL;
  632.         }
  633.     } else {
  634.         panic(0, "Unknown field value type %d.", ret);
  635.     }
  636.     return decoded;
  637. }
  638. /* Cache-directive is defined in 8.4.2.15 */
  639. static Octstr *unpack_cache_directive(ParseContext *context)
  640. {
  641.     Octstr *decoded = NULL;
  642.     int ret;
  643.     int val;
  644.     ret = field_value(context, &val);
  645.     if (parse_error(context) || ret == WSP_FIELD_VALUE_DATA) {
  646.         warning(0, "Bad cache-directive");
  647.         goto error;
  648.     }
  649.     if (ret == WSP_FIELD_VALUE_ENCODED) {
  650.         decoded = wsp_cache_control_to_string(val);
  651.         if (!decoded) {
  652.             warning(0, "Bad cache-directive 0x%02x.", val);
  653.             goto error;
  654.         }
  655.         octstr_append_char(decoded, '=');
  656.         switch (val) {
  657.         case WSP_CACHE_CONTROL_NO_CACHE:
  658.         case WSP_CACHE_CONTROL_PRIVATE:
  659.             if (parse_octets_left(context) == 0) {
  660.                 warning(0, "Too short cache-directive");
  661.                 goto error;
  662.             }
  663.             octstr_append_char(decoded, '"');
  664.             do {
  665.                 Octstr *fieldname = unpack_field_name(context);
  666.                 if (!fieldname) {
  667.                     warning(0, "Bad field name in cache directive");
  668.                     goto error;
  669.                 }
  670.                 octstr_append(decoded, fieldname);
  671.                 octstr_destroy(fieldname);
  672.                 if (parse_octets_left(context) > 0) {
  673.                     octstr_append_char(decoded, ',');
  674.                     octstr_append_char(decoded, ' ');
  675.                 }
  676.             } while (parse_octets_left(context) > 0 &&
  677.                      !parse_error(context));
  678.             octstr_append_char(decoded, '"');
  679.             break;
  680.         case WSP_CACHE_CONTROL_MAX_AGE:
  681.         case WSP_CACHE_CONTROL_MAX_STALE:
  682.         case WSP_CACHE_CONTROL_MIN_FRESH:
  683.             {
  684.                 Octstr *seconds;
  685.                 seconds = unpack_integer_value(context);
  686.                 if (!seconds) {
  687.                     warning(0, "Bad integer value in cache directive");
  688.                     goto error;
  689.                 }
  690.                 octstr_append(decoded, seconds);
  691.                 octstr_destroy(seconds);
  692.             }
  693.             break;
  694.         default:
  695.             warning(0, "Unexpected value 0x%02x in cache directive.", val);
  696.             break;
  697.         }
  698.     } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
  699.         /* XXX: WSP grammar seems wrong here.  It works out
  700.          * to Token-text followed by Parameter.  But the
  701.          * grammar in RFC2616 works out to a key = value
  702.          * pair, i.e. only a Parameter. */
  703.         decoded = parse_get_nul_string(context);
  704.         if (!decoded) {
  705.             warning(0, "Format error in cache-control.");
  706.             return NULL;
  707.         }
  708.         /* Yes, the grammar allows only one */
  709.         unpack_parameter(context, decoded);
  710.     } else {
  711.         panic(0, "Unknown field value type %d.", ret);
  712.     }
  713.     return decoded;
  714. error:
  715.     octstr_destroy(decoded);
  716.     return NULL;
  717. }
  718. /* Retry-after is defined in 8.4.2.44 */
  719. static Octstr *unpack_retry_after(ParseContext *context)
  720. {
  721.     int selector;
  722.     selector = parse_get_char(context);
  723.     if (selector == ABSOLUTE_TIME) {
  724.         return unpack_date_value(context);
  725.     } else if (selector == RELATIVE_TIME) {
  726.         return unpack_integer_value(context);
  727.     } else {
  728.         warning(0, "Cannot parse retry-after value.");
  729.         return NULL;
  730.     }
  731. }
  732. /* Disposition is defined in 8.4.2.53 */
  733. static Octstr *unpack_disposition(ParseContext *context)
  734. {
  735.     Octstr *decoded = NULL;
  736.     int selector;
  737.     selector = parse_get_char(context) - 128;
  738.     decoded = wsp_disposition_to_string(selector);
  739.     if (!decoded) {
  740.         warning(0, "Cannot parse content-disposition value.");
  741.         return NULL;
  742.     }
  743.     unpack_all_parameters(context, decoded);
  744.     return decoded;
  745. }
  746. /* Range-value is defined in 8.4.2.42 */
  747. static Octstr *unpack_range_value(ParseContext *context)
  748. {
  749.     Octstr *decoded = NULL;
  750.     int selector;
  751.     unsigned long first_byte_pos, last_byte_pos, suffix_length;
  752.     selector = parse_get_char(context);
  753.     if (selector == BYTE_RANGE) {
  754.         first_byte_pos = parse_get_uintvar(context);
  755.         if (parse_error(context))
  756.             goto error;
  757.         decoded = octstr_create("bytes = ");
  758.         octstr_append_decimal(decoded, first_byte_pos);
  759.         octstr_append_char(decoded, '-');
  760.         last_byte_pos = parse_get_uintvar(context);
  761.         if (parse_error(context)) {
  762.             /* last_byte_pos is optional */
  763.             parse_clear_error(context);
  764.         } else {
  765.             octstr_append_decimal(decoded, last_byte_pos);
  766.         }
  767.     } else if (selector == SUFFIX_BYTE_RANGE) {
  768.         suffix_length = parse_get_uintvar(context);
  769.         if (parse_error(context))
  770.             goto error;
  771.         decoded = octstr_create("bytes = -");
  772.         octstr_append_decimal(decoded, suffix_length);
  773.     } else {
  774.         goto error;
  775.     }
  776.     return decoded;
  777. error:
  778.     warning(0, "Bad format for range-value.");
  779.     octstr_destroy(decoded);
  780.     return NULL;
  781. }
  782. /* Warning-value is defined in 8.4.2.51 */
  783. static Octstr *unpack_warning_value(ParseContext *context)
  784. {
  785.     Octstr *decoded = NULL;
  786.     Octstr *warn_code = NULL;
  787.     Octstr *warn_agent = NULL;
  788.     Octstr *warn_text = NULL;
  789.     unsigned char quote = '"';
  790.     warn_code = unpack_integer_value(context);
  791.     warn_agent = parse_get_nul_string(context);
  792.     if (warn_agent && octstr_get_char(warn_agent, 0) == WSP_QUOTE)
  793.         octstr_delete(warn_agent, 0, 1);
  794.     warn_text = parse_get_nul_string(context);
  795.     if (warn_text && octstr_get_char(warn_text, 0) == WSP_QUOTE)
  796.         octstr_delete(warn_text, 0, 1);
  797.     if (octstr_get_char(warn_text, 0) != quote)
  798.         octstr_insert_data(warn_text, 0, &quote, 1);
  799.     if (octstr_get_char(warn_text, octstr_len(warn_text) - 1) != quote)
  800.         octstr_append_char(warn_text, quote);
  801.     if (parse_error(context) || !warn_agent || !warn_text)
  802.         goto error;
  803.     decoded = octstr_create("");
  804.     octstr_append(decoded, warn_code);
  805.     octstr_append_char(decoded, ' ');
  806.     octstr_append(decoded, warn_agent);
  807.     octstr_append_char(decoded, ' ');
  808.     octstr_append(decoded, warn_text);
  809.     octstr_destroy(warn_agent);
  810.     octstr_destroy(warn_code);
  811.     octstr_destroy(warn_text);
  812.     return decoded;
  813. error:
  814.     warning(0, "Bad format for warning-value.");
  815.     octstr_destroy(warn_agent);
  816.     octstr_destroy(warn_code);
  817.     octstr_destroy(warn_text);
  818.     octstr_destroy(decoded);
  819.     return NULL;
  820. }
  821. static void unpack_well_known_field(List *unpacked, int field_type,
  822.                                     ParseContext *context)
  823. {
  824.     int val, ret;
  825.     unsigned char *headername = NULL;
  826.     unsigned char *ch = NULL;
  827.     Octstr *decoded = NULL;
  828.     ret = field_value(context, &val);
  829.     if (parse_error(context)) {
  830.         warning(0, "Faulty header, skipping remaining headers.");
  831.         parse_skip_to_limit(context);
  832.         return;
  833.     }
  834.     headername = wsp_header_to_cstr(field_type);
  835.     /* headername can still be NULL.  This is checked after parsing
  836.      * the field value.  We want to parse the value before exiting,
  837.      * so that we are ready for the next header. */
  838.     /* The following code must set "ch" or "decoded" to a non-NULL
  839.      * value if the header is valid. */
  840.     if (ret == WSP_FIELD_VALUE_NUL_STRING) {
  841.         /* We allow any header to have a text value, even if that
  842.          * is not defined in the grammar.  Be generous in what
  843.          * you accept, etc. */
  844.         /* This covers Text-string, Token-Text, and Uri-value rules */
  845.         decoded = parse_get_nul_string(context);
  846.     } else if (ret == WSP_FIELD_VALUE_ENCODED) {
  847.         switch (field_type) {
  848.         case WSP_HEADER_ACCEPT:
  849.         case WSP_HEADER_CONTENT_TYPE:
  850.             ch = wsp_content_type_to_cstr(val);
  851.             if (!ch)
  852.                 warning(0, "Unknown content type 0x%02x.", val);
  853.             break;
  854.         case WSP_HEADER_ACCEPT_CHARSET:
  855.             ch = wsp_charset_to_cstr(val);
  856.             if (!ch)
  857.                 warning(0, "Unknown charset 0x%02x.", val);
  858.             break;
  859.         case WSP_HEADER_ACCEPT_ENCODING:
  860.         case WSP_HEADER_CONTENT_ENCODING:
  861.             ch = wsp_encoding_to_cstr(val);
  862.             if (!ch)
  863.                 warning(0, "Unknown encoding 0x%02x.", val);
  864.             break;
  865.         case WSP_HEADER_ACCEPT_LANGUAGE:
  866.         case WSP_HEADER_CONTENT_LANGUAGE:
  867.             ch = wsp_language_to_cstr(val);
  868.             if (!ch)
  869.                 warning(0, "Unknown language 0x%02x.", val);
  870.             break;
  871.         case WSP_HEADER_ACCEPT_RANGES:
  872.             ch = wsp_ranges_to_cstr(val);
  873.             if (!ch)
  874.                 warning(0, "Unknown ranges value 0x%02x.", val);
  875.             break;
  876.         case WSP_HEADER_AGE:
  877.         case WSP_HEADER_CONTENT_LENGTH:
  878.         case WSP_HEADER_MAX_FORWARDS:
  879.             /* Short-integer version of Integer-value */
  880.             decoded = octstr_create("");
  881.             octstr_append_decimal(decoded, val);
  882.             break;
  883.         case WSP_HEADER_ALLOW:
  884.         case WSP_HEADER_PUBLIC:
  885.             ch = wsp_method_to_cstr(val);
  886.             if (!ch) {
  887.                 /* FIXME Support extended methods */
  888.                 warning(0, "Unknown method 0x%02x.", val);
  889.             }
  890.             break;
  891.         case WSP_HEADER_CACHE_CONTROL:
  892.             ch = wsp_cache_control_to_cstr(val);
  893.             if (!ch)
  894.                 warning(0, "Unknown cache-control value 0x%02x.", val);
  895.             break;
  896.         case WSP_HEADER_CONNECTION:
  897.             ch = wsp_connection_to_cstr(val);
  898.             if (!ch)
  899.                 warning(0, "Unknown connection value 0x%02x.", val);
  900.             break;
  901.         case WSP_HEADER_PRAGMA:
  902.             if (val == 0)
  903.                 ch = "no-cache";
  904.             else
  905.                 warning(0, "Unknown pragma value 0x%02x.", val);
  906.             break;
  907.         case WSP_HEADER_TRANSFER_ENCODING:
  908.             ch = wsp_transfer_encoding_to_cstr(val);
  909.             if (!ch)
  910.                 warning(0, "Unknown transfer encoding value 0x%02x.", val);
  911.             break;
  912.         case WSP_HEADER_VARY:
  913.             ch = wsp_header_to_cstr(val);
  914.             if (!ch)
  915.                 warning(0, "Unknown Vary field name 0x%02x.", val);
  916.             break;
  917.         case WSP_HEADER_WARNING:
  918.             decoded = octstr_create("");
  919.             octstr_append_decimal(decoded, val);
  920.             break;
  921.         default:
  922.             if (headername) {
  923.                 warning(0, "Did not expect short-integer with "
  924.                         "'%s' header, skipping.", headername);
  925.             }
  926.             break;
  927.         }
  928.     } else if (ret == WSP_FIELD_VALUE_DATA) {
  929.         switch (field_type) {
  930.         case WSP_HEADER_ACCEPT:
  931.         case WSP_HEADER_CONTENT_TYPE:
  932.             /* Content-general-form and Accept-general-form
  933.              * are defined separately in WSP, but their
  934.              * definitions are equivalent. */
  935.             decoded = unpack_accept_general_form(context);
  936.             break;
  937.         case WSP_HEADER_ACCEPT_CHARSET:
  938.             decoded = unpack_accept_charset_general_form(context);
  939.             break;
  940.         case WSP_HEADER_ACCEPT_LANGUAGE:
  941.             decoded = unpack_accept_language_general_form(context);
  942.             break;
  943.         case WSP_HEADER_AGE:
  944.         case WSP_HEADER_CONTENT_LENGTH:
  945.         case WSP_HEADER_MAX_FORWARDS:
  946.         case WSP_HEADER_BEARER_INDICATION:
  947.         case WSP_HEADER_ACCEPT_APPLICATION:
  948.             /* Long-integer version of Integer-value */
  949.             {
  950.                 long l = unpack_multi_octet_integer(context,
  951.                                                     parse_octets_left(context));
  952.                 decoded = octstr_create("");
  953.                 octstr_append_decimal(decoded, l);
  954.             }
  955.             break;
  956.         case WSP_HEADER_AUTHORIZATION:
  957.         case WSP_HEADER_PROXY_AUTHORIZATION:
  958.             decoded = unpack_credentials(context);
  959.             break;
  960.         case WSP_HEADER_CACHE_CONTROL:
  961.             decoded = unpack_cache_directive(context);
  962.             break;
  963.         case WSP_HEADER_CONTENT_MD5:
  964.             decoded = parse_get_octets(context,
  965.                                        parse_octets_left(context));
  966.             octstr_binary_to_base64(decoded);
  967.             /* Zap the CR LF sequence at the end */
  968.             octstr_delete(decoded, octstr_len(decoded) - 2, 2);
  969.             break;
  970.         case WSP_HEADER_CONTENT_RANGE:
  971.             decoded = unpack_content_range(context);
  972.             break;
  973.         case WSP_HEADER_DATE:
  974.         case WSP_HEADER_EXPIRES:
  975.         case WSP_HEADER_IF_MODIFIED_SINCE:
  976.         case WSP_HEADER_IF_RANGE:
  977.         case WSP_HEADER_IF_UNMODIFIED_SINCE:
  978.         case WSP_HEADER_LAST_MODIFIED:
  979.             /* Back up to get the length byte again */
  980.             parse_skip(context, -1);
  981.             decoded = unpack_date_value(context);
  982.             break;
  983.         case WSP_HEADER_PRAGMA:
  984.             /* The value is a bare Parameter, without a preceding
  985.              * header body.  unpack_parameter wasn't really
  986.              * designed for this.  We work around it here. */
  987.             decoded = octstr_create("");
  988.             if (unpack_parameter(context, decoded) < 0) {
  989.                 octstr_destroy(decoded);
  990.                 decoded = NULL;
  991.             } else {
  992.                 /* Remove the leading "; " */
  993.                 octstr_delete(decoded, 0, 2);
  994.             }
  995.             break;
  996.         case WSP_HEADER_PROXY_AUTHENTICATE:
  997.         case WSP_HEADER_WWW_AUTHENTICATE:
  998.             decoded = unpack_challenge(context);
  999.             break;
  1000.         case WSP_HEADER_RANGE:
  1001.             decoded = unpack_range_value(context);
  1002.             break;
  1003.         case WSP_HEADER_RETRY_AFTER:
  1004.             decoded = unpack_retry_after(context);
  1005.             break;
  1006.         case WSP_HEADER_WARNING:
  1007.             decoded = unpack_warning_value(context);
  1008.             break;
  1009.         case WSP_HEADER_CONTENT_DISPOSITION:
  1010.             decoded = unpack_disposition(context);
  1011.             break;
  1012.         default:
  1013.             if (headername) {
  1014.                 warning(0, "Did not expect value-length with "
  1015.                         "'%s' header, skipping.", headername);
  1016.             }
  1017.             break;
  1018.         }
  1019.         if (headername && parse_octets_left(context) > 0) {
  1020.             warning(0, "WSP: %s: skipping %ld trailing octets.",
  1021.                     headername, parse_octets_left(context));
  1022.         }
  1023.         parse_skip_to_limit(context);
  1024.         parse_pop_limit(context);
  1025.     } else {
  1026.         panic(0, "Unknown field-value type %d.", ret);
  1027.     }
  1028.     if (ch == NULL && decoded != NULL)
  1029.         ch = octstr_get_cstr(decoded);
  1030.     if (ch == NULL)
  1031.         goto value_error;
  1032.     if (!headername) {
  1033.         warning(0, "Unknown header number 0x%02x.", field_type);
  1034.         goto value_error;
  1035.     }
  1036.     http_header_add(unpacked, headername, ch);
  1037.     octstr_destroy(decoded);
  1038.     return;
  1039. value_error:
  1040.     warning(0, "Skipping faulty header.");
  1041.     octstr_destroy(decoded);
  1042. }
  1043. static void unpack_app_header(List *unpacked, ParseContext *context)
  1044. {
  1045.     Octstr *header = NULL;
  1046.     Octstr *value = NULL;
  1047.     header = parse_get_nul_string(context);
  1048.     value = parse_get_nul_string(context);
  1049.     if (header && value) {
  1050.         http_header_add(unpacked, octstr_get_cstr(header),
  1051.                         octstr_get_cstr(value));
  1052.     }
  1053.     if (parse_error(context))
  1054.         warning(0, "Error parsing application-header.");
  1055.     octstr_destroy(header);
  1056.     octstr_destroy(value);
  1057. }
  1058. List *wsp_headers_unpack(Octstr *headers, int content_type_present)
  1059. {
  1060.     ParseContext *context;
  1061.     int byte;
  1062.     List *unpacked;
  1063.     int code_page;
  1064.     unpacked = http_create_empty_headers();
  1065.     context = parse_context_create(headers);
  1066.     if (octstr_len(headers) > 0) {
  1067.         debug("wsp", 0, "WSP: decoding headers:");
  1068.         octstr_dump(headers, 0);
  1069.     }
  1070.     if (content_type_present)
  1071.         unpack_well_known_field(unpacked,
  1072.                                 WSP_HEADER_CONTENT_TYPE, context);
  1073.     code_page = 1;   /* default */
  1074.     while (parse_octets_left(context) > 0 && !parse_error(context)) {
  1075.         byte = parse_get_char(context);
  1076.         if (byte == 127 || (byte >= 1 && byte <= 31)) {
  1077.             if (byte == 127)
  1078.                 code_page = parse_get_char(context);
  1079.             else
  1080.                 code_page = byte;
  1081.             if (code_page == 1)
  1082.                 info(0, "Returning to code page 1 (default).");
  1083.             else {
  1084.                 warning(0, "Shift to unknown code page %d.",
  1085.                         code_page);
  1086.                 warning(0, "Will try to skip headers until "
  1087.                         "next known code page.");
  1088.             }
  1089.         } else if (byte >= 128) {  /* well-known-header */
  1090.             if (code_page == 1)
  1091.                 unpack_well_known_field(unpacked, byte - 128, context);
  1092.             else {
  1093.                 debug("wsp", 0, "Skipping field 0x%02x.", byte);
  1094.                 skip_field_value(context);
  1095.             }
  1096.         } else if (byte > 31 && byte < 127) {
  1097.             /* Un-parse the character we just read */
  1098.             parse_skip(context, -1);
  1099.             unpack_app_header(unpacked, context);
  1100.         } else {
  1101.             warning(0, "Unsupported token or header (start 0x%x)", byte);
  1102.             break;
  1103.         }
  1104.     }
  1105.     if (list_len(unpacked) > 0) {
  1106.         long i;
  1107.         debug("wsp", 0, "WSP: decoded headers:");
  1108.         for (i = 0; i < list_len(unpacked); i++) {
  1109.             Octstr *header = list_get(unpacked, i);
  1110.             debug("wsp", 0, octstr_get_cstr(header));
  1111.         }
  1112.         debug("wsp", 0, "WSP: End of decoded headers.");
  1113.     }
  1114.     parse_context_destroy(context);
  1115.     return unpacked;
  1116. }
  1117. /**********************************************************************/
  1118. /* Start of header packing code (HTTP to WSP)                         */
  1119. /**********************************************************************/
  1120. struct parameter
  1121. {
  1122.     Octstr *key;
  1123.     Octstr *value;
  1124. };
  1125. typedef struct parameter Parameter;
  1126. typedef int header_pack_func_t(Octstr *packed, Octstr *value);
  1127. struct headerinfo
  1128. {
  1129.     /* The WSP_HEADER_* enumeration value for this header */
  1130.     int header;
  1131.     header_pack_func_t *func;
  1132.     /* True if this header type allows multiple elements per
  1133.      * header on the HTTP side. */
  1134.     int allows_list;
  1135. };
  1136. static int pack_accept(Octstr *packet, Octstr *value);
  1137. static int pack_accept_charset(Octstr *packet, Octstr *value);
  1138. static int pack_accept_encoding(Octstr *packet, Octstr *value);
  1139. static int pack_accept_language(Octstr *packet, Octstr *value);
  1140. static int pack_cache_control(Octstr *packet, Octstr *value);
  1141. static int pack_challenge(Octstr *packet, Octstr *value);
  1142. static int pack_connection(Octstr *packet, Octstr *value);
  1143. static int pack_content_disposition(Octstr *packet, Octstr *value);
  1144. static int pack_content_range(Octstr *packet, Octstr *value);
  1145. static int pack_content_type(Octstr *packet, Octstr *value);
  1146. static int pack_credentials(Octstr *packet, Octstr *value);
  1147. static int pack_date(Octstr *packet, Octstr *value);
  1148. static int pack_encoding(Octstr *packet, Octstr *value);
  1149. static int pack_expires(Octstr *packet, Octstr *value);
  1150. static int pack_field_name(Octstr *packet, Octstr *value);
  1151. static int pack_if_range(Octstr *packet, Octstr *value);
  1152. static int pack_integer_string(Octstr *packet, Octstr *value);
  1153. static int pack_language(Octstr *packet, Octstr *value);
  1154. static int pack_md5(Octstr *packet, Octstr *value);
  1155. static int pack_method(Octstr *packet, Octstr *value);
  1156. static int pack_pragma(Octstr *packet, Octstr *value);
  1157. static int pack_range(Octstr *packet, Octstr *value);
  1158. static int pack_range_unit(Octstr *packet, Octstr *value);
  1159. static int pack_retry_after(Octstr *packet, Octstr *value);
  1160. static int pack_text(Octstr *packet, Octstr *value);
  1161. static int pack_transfer_encoding(Octstr *packet, Octstr *value);
  1162. static int pack_uri(Octstr *packet, Octstr *value);
  1163. static int pack_warning(Octstr *packet, Octstr *value);
  1164. /* LIST is a comma-separated list such as is described in the "#rule"
  1165.  * entry of RFC2616 section 2.1. */
  1166. #define LIST 1
  1167. /* BROKEN_LIST is a list of "challenge" or "credentials" elements
  1168.  * such as described in RFC2617.  I call it broken because the
  1169.  * parameters are separated with commas, instead of with semicolons
  1170.  * like everywhere else in HTTP.  Parsing is more difficult because
  1171.  * commas are also used to separate list elements. */
  1172. #define BROKEN_LIST 2
  1173. #define TABLE_SIZE(table) ((long)(sizeof(table) / sizeof(table[0])))
  1174. struct headerinfo headerinfo[] =
  1175.     {
  1176.         {
  1177.             WSP_HEADER_ACCEPT, pack_accept, LIST
  1178.         },
  1179.         { WSP_HEADER_ACCEPT_CHARSET, pack_accept_charset, LIST },
  1180.         { WSP_HEADER_ACCEPT_ENCODING, pack_accept_encoding, LIST },
  1181.         { WSP_HEADER_ACCEPT_LANGUAGE, pack_accept_language, LIST },
  1182.         { WSP_HEADER_ACCEPT_RANGES, pack_range_unit, LIST },
  1183.         { WSP_HEADER_AGE, pack_integer_string, 0 },
  1184.         /* pack_method is slightly too general because Allow is only
  1185.          * supposed to encode well-known-methods. */
  1186.         { WSP_HEADER_ALLOW, pack_method, LIST },
  1187.         { WSP_HEADER_AUTHORIZATION, pack_credentials, BROKEN_LIST },
  1188.         { WSP_HEADER_CACHE_CONTROL, pack_cache_control, LIST },
  1189.         { WSP_HEADER_CONNECTION, pack_connection, LIST },
  1190.         { WSP_HEADER_CONTENT_BASE, pack_uri, 0 },
  1191.         { WSP_HEADER_CONTENT_ENCODING, pack_encoding, LIST },
  1192.         { WSP_HEADER_CONTENT_LANGUAGE, pack_language, LIST },
  1193.         { WSP_HEADER_CONTENT_LENGTH, pack_integer_string, 0 },
  1194.         { WSP_HEADER_CONTENT_LOCATION, pack_uri, 0 },
  1195.         { WSP_HEADER_CONTENT_MD5, pack_md5, 0 },
  1196.         { WSP_HEADER_CONTENT_RANGE, pack_content_range, 0 },
  1197.         { WSP_HEADER_CONTENT_TYPE, pack_content_type, 0 },
  1198.         { WSP_HEADER_DATE, pack_date, 0 },
  1199.         { WSP_HEADER_ETAG, pack_text, 0 },
  1200.         { WSP_HEADER_EXPIRES, pack_expires, 0 },
  1201.         { WSP_HEADER_FROM, pack_text, 0 },
  1202.         { WSP_HEADER_HOST, pack_text, 0 },
  1203.         { WSP_HEADER_IF_MODIFIED_SINCE, pack_date, 0 },
  1204.         { WSP_HEADER_IF_MATCH, pack_text, 0 },
  1205.         { WSP_HEADER_IF_NONE_MATCH, pack_text, 0 },
  1206.         { WSP_HEADER_IF_RANGE, pack_if_range, 0 },
  1207.         { WSP_HEADER_IF_UNMODIFIED_SINCE, pack_date, 0 },
  1208.         { WSP_HEADER_LAST_MODIFIED, pack_date, 0 },
  1209.         { WSP_HEADER_LOCATION, pack_uri, 0 },
  1210.         { WSP_HEADER_MAX_FORWARDS, pack_integer_string, 0 },
  1211.         { WSP_HEADER_PRAGMA, pack_pragma, LIST },
  1212.         { WSP_HEADER_PROXY_AUTHENTICATE, pack_challenge, BROKEN_LIST },
  1213.         { WSP_HEADER_PROXY_AUTHORIZATION, pack_credentials, BROKEN_LIST },
  1214.         { WSP_HEADER_PUBLIC, pack_method, LIST },
  1215.         { WSP_HEADER_RANGE, pack_range, 0 },
  1216.         { WSP_HEADER_REFERER, pack_uri, 0 },
  1217.         { WSP_HEADER_RETRY_AFTER, pack_retry_after, 0 },
  1218.         { WSP_HEADER_SERVER, pack_text, 0 },
  1219.         { WSP_HEADER_TRANSFER_ENCODING, pack_transfer_encoding, LIST },
  1220.         { WSP_HEADER_UPGRADE, pack_text, LIST },
  1221.         { WSP_HEADER_USER_AGENT, pack_text, 0 },
  1222.         { WSP_HEADER_VARY, pack_field_name, LIST },
  1223.         { WSP_HEADER_VIA, pack_text, LIST },
  1224.         { WSP_HEADER_WARNING, pack_warning, LIST },
  1225.         { WSP_HEADER_WWW_AUTHENTICATE, pack_challenge, BROKEN_LIST },
  1226.         { WSP_HEADER_CONTENT_DISPOSITION, pack_content_disposition, 0 },
  1227.         { WSP_HEADER_PUSH_FLAG, pack_integer_string, 0},
  1228.         { WSP_HEADER_X_WAP_CONTENT_URI, pack_uri, 0},
  1229.         { WSP_HEADER_X_WAP_INITIATOR_URI, pack_uri, 0},
  1230.         { WSP_HEADER_X_WAP_APPLICATION_ID, pack_integer_string, 0}
  1231.     };
  1232. static Parameter *parm_create(Octstr *key, Octstr *value)
  1233. {
  1234.     Parameter *parm;
  1235.     parm = gw_malloc(sizeof(*parm));
  1236.     parm->key = key;
  1237.     parm->value = value;
  1238.     return parm;
  1239. }
  1240. static void parm_destroy(Parameter *parm)
  1241. {
  1242.     if (parm == NULL)
  1243.         return;
  1244.     octstr_destroy(parm->key);
  1245.     octstr_destroy(parm->value);
  1246.     gw_free(parm);
  1247. }
  1248. static void parm_destroy_item(void *parm)
  1249. {
  1250.     parm_destroy(parm);
  1251. }
  1252. static Parameter *parm_parse(Octstr *value)
  1253. {
  1254.     long pos;
  1255.     Octstr *key, *val;
  1256.     pos = octstr_search_char(value, '=', 0);
  1257.     if (pos > 0) {
  1258.         key = octstr_copy(value, 0, pos);
  1259.         val = octstr_copy(value, pos + 1, octstr_len(value) - pos);
  1260.         octstr_strip_blanks(key);
  1261.         octstr_strip_blanks(val);
  1262.     } else {
  1263.         key = octstr_duplicate(value);
  1264.         val = NULL;
  1265.     }
  1266.     return parm_create(key, val);
  1267. }
  1268. /* Many HTTP field elements can take parameters in a standardized
  1269.  * form: parameters appear after the main value, each is introduced
  1270.  * by a semicolon (;), and consists of a key=value pair or just
  1271.  * a key, where the key is a token and the value is either a token
  1272.  * or a quoted-string.
  1273.  * The main value itself is a series of tokens, separators, and
  1274.  * quoted-strings.
  1275.  *
  1276.  * This function will take such a field element, and remove all
  1277.  * parameters from it.  The parameters are returned as a List
  1278.  * of Parameter, where the value field is left NULL
  1279.  * if the parameter was just a key.
  1280.  * It returns NULL if there were no parameters.
  1281.  */
  1282. static List *strip_parameters(Octstr *value)
  1283. {
  1284.     long pos;
  1285.     long len;
  1286.     int c;
  1287.     long end;
  1288.     List *parms;
  1289.     long firstparm;
  1290.     len = octstr_len(value);
  1291.     /* Find the start of the first parameter. */
  1292.     for (pos = 0; pos < len; pos++) {
  1293.         c = octstr_get_char(value, pos);
  1294.         if (c == ';')
  1295.             break;
  1296.         else if (c == '"')
  1297.             pos += http_header_quoted_string_len(value, pos) - 1;
  1298.     }
  1299.     if (pos >= len)
  1300.         return NULL;   /* no parameters */
  1301.     parms = list_create();
  1302.     firstparm = pos;
  1303.     for (pos++; pos > 0 && pos < len; pos++) {
  1304.         Octstr *key = NULL;
  1305.         Octstr *val = NULL;
  1306.         end = octstr_search_char(value, '=', pos);
  1307.         if (end < 0)
  1308.             end = octstr_search_char(value, ';', pos);
  1309.         if (end < 0)
  1310.             end = octstr_len(value);
  1311.         key = octstr_copy(value, pos, end - pos);
  1312.         octstr_strip_blanks(key);
  1313.         pos = end;
  1314.         if (octstr_get_char(value, pos) == '=') {
  1315.             pos++;
  1316.             while (isspace(octstr_get_char(value, pos)))
  1317.                 pos++;
  1318.             if (octstr_get_char(value, pos) == '"')
  1319.                 end = pos + http_header_quoted_string_len(value, pos);
  1320.             else
  1321.                 end = octstr_search_char(value, ';', pos);
  1322.             if (end < 0)
  1323.                 end = octstr_len(value);
  1324.             val = octstr_copy(value, pos, end - pos);
  1325.             octstr_strip_blanks(val);
  1326.             pos = end;
  1327.             pos = octstr_search_char(value, ';', pos);
  1328.         }
  1329.         list_append(parms, parm_create(key, val));
  1330.     }
  1331.     octstr_delete(value, firstparm, octstr_len(value) - firstparm);
  1332.     octstr_strip_blanks(value);
  1333.     return parms;
  1334. }
  1335. static int pack_text(Octstr *packed, Octstr *text)
  1336. {
  1337.     /* This check catches 0-length strings as well, because
  1338.      * octstr_get_char will return -1. */
  1339.     if (octstr_get_char(text, 0) >= 128 || octstr_get_char(text, 0) < 32)
  1340.         octstr_append_char(packed, WSP_QUOTE);
  1341.     octstr_append(packed, text);
  1342.     octstr_append_char(packed, 0);
  1343.     return 0;
  1344. }
  1345. /* Pack text as Quoted-string if it starts with a " character.
  1346.  * Pack it as Text-string otherwise. */
  1347. static void pack_quoted_string(Octstr *packed, Octstr *text)
  1348. {
  1349.     octstr_append(packed, text);
  1350.     if (octstr_get_char(text, octstr_len(text) - 1) == '"' &&
  1351.         octstr_get_char(text, 0) == '"')
  1352.         octstr_delete(packed, octstr_len(packed) - 1, 1);
  1353.     octstr_append_char(packed, 0);
  1354. }
  1355. /* Is this char in the 'separators' set defined by HTTP? */
  1356. static int is_separator_char(int c)
  1357. {
  1358.     switch (c) {
  1359.     case '(':
  1360.     case ')':
  1361.     case '<':
  1362.     case '>':
  1363.     case '@':
  1364.     case ',':
  1365.     case ';':
  1366.     case ':':
  1367.     case '\':
  1368.     case '"':
  1369.     case '/':
  1370.     case '[':
  1371.     case ']':
  1372.     case '?':
  1373.     case '=':
  1374.     case '{':
  1375.     case '}':
  1376.     case 32:  /* SP */
  1377.     case 9:   /* HT */
  1378.         return 1;
  1379.     default:
  1380.         return 0;
  1381.     }
  1382. }
  1383. /* Is this char part of a 'token' as defined by HTTP? */
  1384. static int is_token_char(int c)
  1385. {
  1386.     return c >= 32 && c < 127 && !is_separator_char(c);
  1387. }
  1388. /* Is this string a 'token' as defined by HTTP? */
  1389. static int is_token(Octstr *token)
  1390. {
  1391.     return octstr_len(token) > 0 &&
  1392.            octstr_check_range(token, 0, octstr_len(token), is_token_char);
  1393. }
  1394. /* We represent qvalues as integers from 0 through 1000, rather than
  1395.  * as floating values. */
  1396. static int parse_qvalue(Octstr *value)
  1397. {
  1398.     int qvalue;
  1399.     if (value == NULL)
  1400.         return -1;
  1401.     if (!isdigit(octstr_get_char(value, 0)))
  1402.         return -1;
  1403.     qvalue = (octstr_get_char(value, 0) - '0') * 1000;
  1404.     if (octstr_get_char(value, 1) != '.')
  1405.         goto gotvalue;
  1406.     if (!isdigit(octstr_get_char(value, 2)))
  1407.         goto gotvalue;
  1408.     qvalue += (octstr_get_char(value, 2) - '0') * 100;
  1409.     if (!isdigit(octstr_get_char(value, 3)))
  1410.         goto gotvalue;
  1411.     qvalue += (octstr_get_char(value, 3) - '0') * 10;
  1412.     if (!isdigit(octstr_get_char(value, 4)))
  1413.         goto gotvalue;
  1414.     qvalue += (octstr_get_char(value, 4) - '0');
  1415. gotvalue:
  1416.     if (qvalue < 0 || qvalue > 1000)
  1417.         return -1;
  1418.     return qvalue;
  1419. }
  1420. static int get_qvalue(List *parms, int default_qvalue)
  1421. {
  1422.     long i;
  1423.     Parameter *parm;
  1424.     int qvalue;
  1425.     for (i = 0; i < list_len(parms); i++) {
  1426.         parm = list_get(parms, i);
  1427.         if (octstr_str_compare(parm->key, "q") == 0 ||
  1428.             octstr_str_compare(parm->key, "Q") == 0) {
  1429.             qvalue = parse_qvalue(parm->value);
  1430.             if (qvalue >= 0)
  1431.                 return qvalue;
  1432.         }
  1433.     }
  1434.     return default_qvalue;
  1435. }
  1436. static int pack_qvalue(Octstr *packed, int qvalue)
  1437. {
  1438.     /* "Quality factor 1 is the default value and shall never
  1439.      * be sent." */
  1440.     if (qvalue == 1000)
  1441.         return -1;
  1442.     /* Remember that our qvalues are already multiplied by 1000. */
  1443.     if (qvalue % 10 == 0)
  1444.         qvalue = qvalue / 10 + 1;
  1445.     else
  1446.         qvalue = qvalue + 100;
  1447.     octstr_append_uintvar(packed, qvalue);
  1448.     return 0;
  1449. }
  1450. /* Pack value as a Value-length followed by the encoded value. */
  1451. static void pack_value(Octstr *packed, Octstr *encoded)
  1452. {
  1453.     long len;
  1454.     len = octstr_len(encoded);
  1455.     if (len <= 30)
  1456.         octstr_append_char(packed, len);
  1457.     else {
  1458.         octstr_append_char(packed, 31);
  1459.         octstr_append_uintvar(packed, len);
  1460.     }
  1461.     octstr_append(packed, encoded);
  1462. }
  1463. static void pack_long_integer(Octstr *packed, unsigned long integer)
  1464. {
  1465.     long oldlen = octstr_len(packed);
  1466.     unsigned char octet;
  1467.     long len;
  1468.     if (integer == 0) {
  1469. /* The Multi-octet-integer has to be at least 1 octet long. */
  1470. octstr_append_char(packed, 1); /* length */
  1471. octstr_append_char(packed, 0); /* value */
  1472. return;
  1473.     }
  1474.     /* Encode it back-to-front, by repeatedly inserting
  1475.      * at the same position, because that's easier. */
  1476.     for (len = 0; integer != 0; integer >>= 8, len++) {
  1477.         octet = integer & 0xff;
  1478.         octstr_insert_data(packed, oldlen, &octet, 1);
  1479.     }
  1480.     octet = len;
  1481.     octstr_insert_data(packed, oldlen, &octet, 1);
  1482. }
  1483. static void pack_short_integer(Octstr *packed, unsigned long integer)
  1484. {
  1485.     gw_assert(integer <= MAX_SHORT_INTEGER);
  1486.     octstr_append_char(packed, integer + 0x80);
  1487. }
  1488. static void pack_integer_value(Octstr *packed, unsigned long integer)
  1489. {
  1490.     if (integer <= MAX_SHORT_INTEGER)
  1491.         pack_short_integer(packed, integer);
  1492.     else
  1493.         pack_long_integer(packed, integer);
  1494. }
  1495. static int pack_integer_string(Octstr *packed, Octstr *value)
  1496. {
  1497.     unsigned long integer;
  1498.     long pos;
  1499.     int c;
  1500.     int digit;
  1501.     integer = 0;
  1502.     for (pos = 0; pos < octstr_len(value); pos++) {
  1503.         c = octstr_get_char(value, pos);
  1504.         if (!isdigit(c))
  1505.             break;
  1506.         digit = c - '0';
  1507.         if (integer > ULONG_MAX / 10)
  1508.             goto overflow;
  1509.         integer *= 10;
  1510.         if (integer > ULONG_MAX - digit)
  1511.             goto overflow;
  1512.         integer += digit;
  1513.     }
  1514.     pack_integer_value(packed, integer);
  1515.     return 0;
  1516. overflow:
  1517.     warning(0, "WSP: Number too large to handle: '%s'.",
  1518.             octstr_get_cstr(value));
  1519.     return -1;
  1520. }
  1521. static void pack_version_value(Octstr *packed, Octstr *version)
  1522. {
  1523.     long major, minor;
  1524.     long pos;
  1525.     pos = octstr_parse_long(&major, version, 0, 10);
  1526.     if (pos < 0 || major < 1 || major > 7)
  1527.         goto usetext;
  1528.     if (pos == octstr_len(version))
  1529.         minor = 15;
  1530.     else {
  1531.         if (octstr_get_char(version, pos) != '.')
  1532.             goto usetext;
  1533.         pos = octstr_parse_long(&minor, version, pos + 1, 10);
  1534.         if (pos != octstr_len(version) || minor < 0 || minor > 14)
  1535.             goto usetext;
  1536.     }
  1537.     pack_short_integer(packed, major << 4 | minor);
  1538.     return;
  1539. usetext:
  1540.     pack_text(packed, version);
  1541. }
  1542. static int pack_constrained_value(Octstr *packed, Octstr *text, long value)
  1543. {
  1544.     if (value >= 0)
  1545.         pack_short_integer(packed, value);
  1546.     else
  1547.         pack_text(packed, text);
  1548.     return 0;
  1549. }
  1550. static void pack_parameter(Octstr *packed, Parameter *parm)
  1551. {
  1552.     long keytoken;
  1553.     long tmp;
  1554.     long start;
  1555.     start = octstr_len(packed);
  1556.     /* Parameter = Typed-parameter | Untyped-parameter */
  1557.     keytoken = wsp_string_to_parameter(parm->key);
  1558.     if (keytoken >= 0) {
  1559.         /* Typed-parameter = Well-known-parameter-token Typed-value */
  1560.         /* Well-known-parameter-token = Integer-value */
  1561.         pack_integer_value(packed, keytoken);
  1562.         /* Typed-value = Compact-value | Text-value */
  1563.         /* First try to pack as Compact-value or No-value.
  1564.          * If that fails, pack as Text-value. */
  1565.         if (parm->value == NULL) {
  1566.             octstr_append_char(packed, 0);  /* No-value */
  1567.             return;
  1568.         } else switch (keytoken) {
  1569.             case 0:   /* q */
  1570.                 tmp = parse_qvalue(parm->value);
  1571.                 if (tmp >= 0) {
  1572.                     if (pack_qvalue(packed, tmp) < 0)
  1573.                         octstr_delete(packed, start,
  1574.                                       octstr_len(packed) - start);
  1575.                     return;
  1576.                 }
  1577.                 break;
  1578.             case 1:  /* charset */
  1579.                 tmp = wsp_string_to_charset(parm->value);
  1580.                 if (tmp >= 0) {
  1581.                     pack_integer_value(packed, tmp);
  1582.                     return;
  1583.                 }
  1584.                 break;
  1585.             case 2:  /* level */
  1586.                 pack_version_value(packed, parm->value);
  1587.                 return;
  1588.             case 3:  /* type */
  1589.                 if (octstr_check_range(parm->value, 0,
  1590.                                        octstr_len(parm->value), 
  1591.        gw_isdigit) &&
  1592.                     pack_integer_string(packed, parm->value) >= 0)
  1593.                     return;
  1594.                 break;
  1595.             case 5:  /* name */
  1596.             case 6:  /* filename */
  1597.                 break;
  1598.             case 7:  /* differences */
  1599.                 if (pack_field_name(packed, parm->value) >= 0)
  1600.                     return;
  1601.                 break;
  1602.             case 8:  /* padding */
  1603.                 if (octstr_parse_long(&tmp, parm->value, 0, 10)
  1604.                     == octstr_len(parm->value) &&
  1605.                     tmp >= 0 && tmp <= MAX_SHORT_INTEGER) {
  1606.                     pack_short_integer(packed, tmp);
  1607.                     return;
  1608.                 }
  1609.                 break;
  1610.             }
  1611.         pack_quoted_string(packed, parm->value);
  1612.     } else {
  1613.         /* Untyped-parameter = Token-text Untyped-value */
  1614.         pack_text(packed, parm->key);
  1615.         /* Untyped-value = Integer-value | Text-value */
  1616.         if (parm->value == NULL) {
  1617.             octstr_append_char(packed, 0);  /* No-value */
  1618.             return;
  1619.         }
  1620.         /* If we can pack as integer, do so. */
  1621.         if (octstr_parse_long(&tmp, parm->value, 0, 10)
  1622.             == octstr_len(parm->value)) {
  1623.             pack_integer_value(packed, tmp);
  1624.         } else {
  1625.             pack_quoted_string(packed, parm->value);
  1626.         }
  1627.     }
  1628. }
  1629. static void pack_parameters(Octstr *packed, List *parms)
  1630. {
  1631.     long i;
  1632.     Parameter *parm;
  1633.     for (i = 0; i < list_len(parms); i++) {
  1634.         parm = list_get(parms, i);
  1635.         pack_parameter(packed, parm);
  1636.     }
  1637. }
  1638. static int pack_uri(Octstr *packed, Octstr *value)
  1639. {
  1640.     pack_text(packed, value);
  1641.     return 0;
  1642. }
  1643. static int pack_md5(Octstr *packed, Octstr *value)
  1644. {
  1645.     Octstr *binary;
  1646.     binary = octstr_duplicate(value);
  1647.     octstr_base64_to_binary(binary);
  1648.     if (octstr_len(binary) != 16) {
  1649.         error(0, "WSP: MD5 value not 128 bits.");
  1650.         return -1;
  1651.     }
  1652.     octstr_append_char(packed, 16);
  1653.     octstr_append(packed, binary);
  1654.     octstr_destroy(binary);
  1655.     return 0;
  1656. }
  1657. /* Actually packs a "Value-length Challenge" */
  1658. /* Relies on http_split_auth_value to have converted the entry to
  1659.  * the normal HTTP parameter format rather than the comma-separated
  1660.  * one used by challenge and credentials. */
  1661. static int pack_challenge(Octstr *packed, Octstr *value)
  1662. {
  1663.     Octstr *encoding = NULL;
  1664.     Octstr *scheme = NULL;
  1665.     Octstr *basic = octstr_imm("Basic");
  1666.     Octstr *realm = octstr_imm("realm");
  1667.     Octstr *parmstring = NULL;
  1668.     List *parms = NULL;
  1669.     Parameter *realmparm = NULL;
  1670.     long realmpos = -1;
  1671.     Octstr *realmval = NULL;
  1672.     long pos;
  1673.     encoding = octstr_create("");
  1674.     /* Get authentication scheme */
  1675.     for (pos = 0; pos < octstr_len(value); pos++) {
  1676.         if (!is_token_char(octstr_get_char(value, pos)))
  1677.             break;
  1678.     }
  1679.     scheme = octstr_copy(value, 0, pos);
  1680.     octstr_strip_blanks(scheme);
  1681.     /* Skip whitespace */
  1682.     while (isspace(octstr_get_char(value, pos)))
  1683.         pos++;
  1684.     if (octstr_case_compare(scheme, basic) == 0) {
  1685.         parmstring = octstr_copy(value, pos, octstr_len(value) - pos);
  1686.         realmparm = parm_parse(parmstring);
  1687.         octstr_append_char(encoding, BASIC_AUTHENTICATION);
  1688.         realmpos = octstr_len(encoding);
  1689.     } else {
  1690.         long i;
  1691.         pack_text(encoding, scheme);
  1692.         realmpos = octstr_len(encoding);
  1693.         /* Find the realm parameter and exclude it */
  1694.         parms = strip_parameters(value);
  1695.         for (i = 0; i < list_len(parms); i++) {
  1696.             Parameter *parm = list_get(parms, i);
  1697.             if (octstr_case_compare(realm, parm->key) == 0) {
  1698.                 realmparm = parm;
  1699.                 list_delete(parms, i, 1);
  1700.                 break;
  1701.             }
  1702.         }
  1703.         pack_parameters(encoding, parms);
  1704.     }
  1705.     /*
  1706.      * In the WSP encoding we have to put the realm value first, but
  1707.      * with non-Basic challenges we don't know if it will come first
  1708.      * in the HTTP header.  So we just start parsing parameters, and
  1709.      * go back and insert the realm value later.  The same technique
  1710.      * is used for Basic authentication to simplify the code.
  1711.      */
  1712.     if (realmparm == NULL ||
  1713.         octstr_case_compare(realmparm->key, realm) != 0 ||
  1714.         realmparm->value == NULL)
  1715.         goto error;
  1716.     /* Zap quote marks */
  1717.     if (octstr_get_char(realmparm->value, 0) == '"' &&
  1718.         octstr_get_char(realmparm->value, octstr_len(realmparm->value) - 1) == '"') {
  1719.         octstr_delete(realmparm->value, 0, 1);
  1720.         octstr_delete(realmparm->value, octstr_len(realmparm->value) - 1, 1);
  1721.     }
  1722.     gw_assert(realmpos >= 0);
  1723.     realmval = octstr_create("");
  1724.     pack_text(realmval, realmparm->value);
  1725.     octstr_insert(encoding, realmval, realmpos);
  1726.     pack_value(packed, encoding);
  1727.     octstr_destroy(encoding);
  1728.     octstr_destroy(scheme);
  1729.     octstr_destroy(parmstring);
  1730.     parm_destroy(realmparm);
  1731.     list_destroy(parms, parm_destroy_item);
  1732.     octstr_destroy(realmval);
  1733.     return 0;
  1734. error:
  1735.     warning(0, "WSP: Cannot parse challenge.");
  1736.     octstr_destroy(encoding);
  1737.     octstr_destroy(scheme);
  1738.     octstr_destroy(parmstring);
  1739.     parm_destroy(realmparm);
  1740.     list_destroy(parms, parm_destroy_item);
  1741.     octstr_destroy(realmval);
  1742.     return -1;
  1743. }
  1744. /* Actually packs a "Value-length Credentials" */
  1745. /* Relies on http_split_auth_value to have converted the entry to
  1746.  * the normal HTTP parameter format rather than the comma-separated
  1747.  * one used by challenge and credentials. */
  1748. static int pack_credentials(Octstr *packed, Octstr *value)
  1749. {
  1750.     Octstr *encoding = NULL;
  1751.     Octstr *scheme = NULL;
  1752.     Octstr *basic = NULL;
  1753.     long pos;
  1754.     encoding = octstr_create("");
  1755.     /* Get authentication scheme */
  1756.     for (pos = 0; pos < octstr_len(value); pos++) {
  1757.         if (!is_token_char(octstr_get_char(value, pos)))
  1758.             break;
  1759.     }
  1760.     scheme = octstr_copy(value, 0, pos);
  1761.     octstr_strip_blanks(scheme);
  1762.     /* Skip whitespace */
  1763.     while (isspace(octstr_get_char(value, pos)))
  1764.         pos++;
  1765.     basic = octstr_imm("Basic");
  1766.     if (octstr_case_compare(scheme, basic) == 0) {
  1767.         Octstr *cookie;
  1768.         Octstr *userid;
  1769.         Octstr *password;
  1770.         octstr_append_char(encoding, BASIC_AUTHENTICATION);
  1771.         cookie = octstr_copy(value, pos, octstr_len(value) - pos);
  1772.         octstr_base64_to_binary(cookie);
  1773.         pos = octstr_search_char(cookie, ':', 0);
  1774.         if (pos < 0) {
  1775.             warning(0, "WSP: bad cookie in credentials '%s'.",
  1776.                     octstr_get_cstr(value));
  1777.             octstr_destroy(cookie);
  1778.             goto error;
  1779.         }
  1780.         userid = octstr_copy(cookie, 0, pos);
  1781.         password = octstr_copy(cookie, pos + 1, octstr_len(cookie) - pos);
  1782.         pack_text(encoding, userid);
  1783.         pack_text(encoding, password);
  1784.         octstr_destroy(cookie);
  1785.         octstr_destroy(userid);
  1786.         octstr_destroy(password);
  1787.     } else {
  1788.         List *parms;
  1789.         pack_text(encoding, scheme);
  1790.         parms = strip_parameters(value);
  1791.         pack_parameters(encoding, parms);
  1792.         list_destroy(parms, parm_destroy_item);
  1793.     }
  1794.     pack_value(packed, encoding);
  1795.     octstr_destroy(encoding);
  1796.     octstr_destroy(scheme);
  1797.     return 0;
  1798. error:
  1799.     octstr_destroy(encoding);
  1800.     octstr_destroy(scheme);
  1801.     return -1;
  1802. }
  1803. static int pack_date(Octstr *packed, Octstr *value)
  1804. {
  1805.     long timeval;
  1806.     timeval = date_parse_http(value);
  1807.     if (timeval < 0) {
  1808.         warning(0, "WSP headers: cannot decode date '%s'",
  1809.                 octstr_get_cstr(value));
  1810.         return -1;
  1811.     }
  1812.     pack_long_integer(packed, timeval);
  1813.     return 0;
  1814. }
  1815. static int pack_connection(Octstr *packed, Octstr *value)
  1816. {
  1817.     return pack_constrained_value(packed, value,
  1818.                                   wsp_string_to_connection(value));
  1819. }
  1820. static int pack_encoding(Octstr *packed, Octstr *value)
  1821. {
  1822.     return pack_constrained_value(packed, value,
  1823.                                   wsp_string_to_encoding(value));
  1824. }
  1825. static int pack_field_name(Octstr *packed, Octstr *value)
  1826. {
  1827.     return pack_constrained_value(packed, value,
  1828.                                   wsp_string_to_header(value));
  1829. }
  1830. static int pack_language(Octstr *packed, Octstr *value)
  1831. {
  1832.     long language;
  1833.     /* Can't use pack_constrained_value here because
  1834.      * language does not necessarily fit in a Short-integer. */
  1835.     language = wsp_string_to_language(value);
  1836.     if (language >= 0)
  1837.         pack_integer_value(packed, language);
  1838.     else
  1839.         pack_text(packed, value);
  1840.     return 0;
  1841. }
  1842. /* Encode value as Well-known-method | Token-text */
  1843. static int pack_method(Octstr *packed, Octstr *value)
  1844. {
  1845.     /* In the future, we will need some way to refer to extended
  1846.      * method names negotiated for this session. */ 
  1847.     return pack_constrained_value(packed, value,
  1848.                                   wsp_string_to_method(value));
  1849. }
  1850. /* Encode value as Accept-ranges-value */
  1851. static int pack_range_unit(Octstr *packed, Octstr *value)
  1852. {
  1853.     return pack_constrained_value(packed, value,
  1854.                                   wsp_string_to_ranges(value));
  1855. }
  1856. /* Encode byte-range-spec | suffix-byte-range-spec as Range-value.
  1857.  * Return position after the parsed spec. */
  1858. static int pack_range_value(Octstr *packed, Octstr *value, long pos)
  1859. {
  1860.     long first_byte_pos;
  1861.     long last_byte_pos;
  1862.     long suffix_length;
  1863.     Octstr *encoding;
  1864.     while (isspace(octstr_get_char(value, pos)))
  1865.         pos++;
  1866.     if (isdigit(octstr_get_char(value, pos))) {
  1867.         /* byte-range-spec */
  1868.         pos = octstr_parse_long(&first_byte_pos, value, pos, 10);
  1869.         if (pos < 0 || first_byte_pos < 0)
  1870.             return -1;
  1871.         while (isspace(octstr_get_char(value, pos)))
  1872.             pos++;
  1873.         if (octstr_get_char(value, pos) != '-')
  1874.             return -1;
  1875.         pos++;
  1876.         while (isspace(octstr_get_char(value, pos)))
  1877.             pos++;
  1878.         if (isdigit(octstr_get_char(value, pos))) {
  1879.             pos = octstr_parse_long(&last_byte_pos, value, pos, 10);
  1880.             if (pos < 0 || last_byte_pos < 0)
  1881.                 return -1;
  1882.         } else {
  1883.             last_byte_pos = -1;
  1884.         }
  1885.         encoding = octstr_create("");
  1886.         octstr_append_char(encoding, BYTE_RANGE);
  1887.         octstr_append_uintvar(encoding, first_byte_pos);
  1888.         if (last_byte_pos >= 0)
  1889.             octstr_append_uintvar(encoding, last_byte_pos);
  1890.         pack_value(packed, encoding);
  1891.         octstr_destroy(encoding);
  1892.     } else if (octstr_get_char(value, pos) == '-') {
  1893.         /* suffix-byte-range-spec */
  1894.         pos++;
  1895.         pos = octstr_parse_long(&suffix_length, value, pos, 10);
  1896.         if (pos < 0 || suffix_length < 0)
  1897.             return -1;
  1898.         encoding = octstr_create("");
  1899.         octstr_append_char(encoding, SUFFIX_BYTE_RANGE);
  1900.         octstr_append_uintvar(encoding, suffix_length);
  1901.         pack_value(packed, encoding);
  1902.         octstr_destroy(encoding);
  1903.     } else
  1904.         return -1;
  1905.     return pos;
  1906. }
  1907. static int pack_transfer_encoding(Octstr *packed, Octstr *value)
  1908. {
  1909.     return pack_constrained_value(packed, value,
  1910.                                   wsp_string_to_transfer_encoding(value));
  1911. }
  1912. /* Also used by pack_content_type  */
  1913. static int pack_accept(Octstr *packed, Octstr *value)
  1914. {
  1915.     List *parms;
  1916.     long media;
  1917.     parms = strip_parameters(value);
  1918.     media = wsp_string_to_content_type(value);
  1919.     /* See if we can fit this in a Constrained-media encoding */
  1920.     if (parms == NULL && media <= MAX_SHORT_INTEGER) {
  1921.         pack_constrained_value(packed, value, media);
  1922.     } else {
  1923.         Octstr *encoding = octstr_create("");
  1924.         if (media >= 0)
  1925.             pack_integer_value(encoding, media);
  1926.         else
  1927.             pack_text(encoding, value);
  1928.         pack_parameters(encoding, parms);
  1929.         pack_value(packed, encoding);
  1930.         octstr_destroy(encoding);
  1931.     }
  1932.     list_destroy(parms, parm_destroy_item);
  1933.     return 0;
  1934. }
  1935. static int pack_accept_charset(Octstr *packed, Octstr *value)
  1936. {
  1937.     List *parms;
  1938.     long charset;
  1939.     long qvalue;
  1940.     parms = strip_parameters(value);
  1941.     charset = wsp_string_to_charset(value);
  1942.     qvalue = 1000;
  1943.     if (parms)
  1944.         qvalue = get_qvalue(parms, qvalue);
  1945.     list_destroy(parms, parm_destroy_item);
  1946.     /* See if we can fit this in a Constrained-charset encoding */
  1947.     if (qvalue == 1000 && charset <= MAX_SHORT_INTEGER) {
  1948.         pack_constrained_value(packed, value, charset);
  1949.     } else {
  1950.         Octstr *encoding = octstr_create("");
  1951.         if (charset >= 0)
  1952.             pack_integer_value(encoding, charset);
  1953.         else
  1954.             pack_text(encoding, value);
  1955.         if (qvalue != 1000)
  1956.             pack_qvalue(encoding, qvalue);
  1957.         pack_value(packed, encoding);
  1958.         octstr_destroy(encoding);
  1959.     }
  1960.     return 0;
  1961. }
  1962. /* WSP 8.4.2.9 does not specify any way to encode parameters for
  1963.  * an Accept-encoding field, but RFC2616 allows q parameters.
  1964.  * We'll have to simplify: qvalue > 0 means encode it, qvalue == 0
  1965.  * means don't encode it.
  1966.  */
  1967. static int pack_accept_encoding(Octstr *packed, Octstr *value)
  1968. {
  1969.     List *parms;
  1970.     int qvalue;
  1971.     qvalue = 1000;   /* default */
  1972.     parms = strip_parameters(value);
  1973.     if (parms)
  1974.         qvalue = get_qvalue(parms, qvalue);
  1975.     list_destroy(parms, parm_destroy_item);
  1976.     if (qvalue > 0) {
  1977.         if (qvalue < 1000)
  1978.             warning(0, "Cannot encode q-value in Accept-Encoding.");
  1979.         pack_encoding(packed, value);
  1980.     } else {
  1981.         warning(0, "Cannot encode q=0 in Accept-Encoding; skipping this encoding.");
  1982.         return -1;
  1983.     }
  1984.     return 0;
  1985. }
  1986. static int pack_accept_language(Octstr *packed, Octstr *value)
  1987. {
  1988.     List *parms;
  1989.     long language;
  1990.     long qvalue;
  1991.     parms = strip_parameters(value);
  1992.     language = wsp_string_to_language(value);
  1993.     qvalue = 1000;
  1994.     if (parms)
  1995.         qvalue = get_qvalue(parms, qvalue);
  1996.     list_destroy(parms, parm_destroy_item);
  1997.     /* See if we can fit this in a Constrained-language encoding. */
  1998.     /* Note that our language table already includes Any-language */
  1999.     if (qvalue == 1000 && language <= MAX_SHORT_INTEGER) {
  2000.         pack_constrained_value(packed, value, language);
  2001.     } else {
  2002.         Octstr *encoding = octstr_create("");
  2003.         if (language >= 0)
  2004.             pack_integer_value(encoding, language);
  2005.         else
  2006.             pack_text(encoding, value);
  2007.         if (qvalue != 1000)
  2008.             pack_qvalue(encoding, qvalue);
  2009.         pack_value(packed, encoding);
  2010.         octstr_destroy(encoding);
  2011.     }
  2012.     return 0;
  2013. }
  2014. static int pack_cache_control(Octstr *packed, Octstr *value)
  2015. {
  2016.     Parameter *parm;
  2017.     long tmp;
  2018.     parm = parm_parse(value);
  2019.     if (parm->value == NULL) {
  2020.         pack_constrained_value(packed, value,
  2021.                                wsp_string_to_cache_control(parm->key));
  2022.     } else {
  2023.         Octstr *encoding = octstr_create("");
  2024.         tmp = wsp_string_to_cache_control(parm->key);
  2025.         if (tmp < 0) {
  2026.             /* According to WSP 8.4.2.15, the format
  2027.              * is "Cache-extension Parameter", and
  2028.              * Cache-extension is a Token-text.
  2029.              * But in HTTP a cache-extension is of
  2030.              * the form token=value, which maps
  2031.              * nicely to Parameter.  So what is
  2032.              * this extra Token-text?  I decided to leave it blank.
  2033.              *  - Richard Braakman
  2034.              */
  2035.             pack_text(encoding, octstr_imm(""));
  2036.             pack_parameter(encoding, parm);
  2037.         } else {
  2038.             int done = 0;
  2039.             Octstr *value_encoding;
  2040.             List *names;
  2041.             Octstr *element;
  2042.             value_encoding = octstr_create("");
  2043.             switch (tmp) {
  2044.             case WSP_CACHE_CONTROL_NO_CACHE:
  2045.             case WSP_CACHE_CONTROL_PRIVATE:
  2046.                 if (octstr_get_char(parm->value, 0) == '"')
  2047.                     octstr_delete(parm->value, 0, 1);
  2048.                 if (octstr_get_char(parm->value, octstr_len(parm->value) - 1) == '"')
  2049.                     octstr_delete(parm->value, octstr_len(parm->value) - 1, 1);
  2050.                 names = http_header_split_value(parm->value);
  2051.                 while ((element = list_consume(names))) {
  2052.                     pack_field_name(value_encoding, element);
  2053.                     octstr_destroy(element);
  2054.                 }
  2055.                 list_destroy(names, octstr_destroy_item);
  2056.                 done = 1;
  2057.                 break;
  2058.             case WSP_CACHE_CONTROL_MAX_AGE:
  2059.             case WSP_CACHE_CONTROL_MAX_STALE:
  2060.             case WSP_CACHE_CONTROL_MIN_FRESH:
  2061.                 if (pack_integer_string(value_encoding, parm->value) >= 0)
  2062.                     done = 1;
  2063.                 break;
  2064.             }
  2065.             if (done) {
  2066.                 pack_short_integer(encoding, tmp);
  2067.                 octstr_append(encoding, value_encoding);
  2068.             } else {
  2069.                 /* See note above */
  2070.                 pack_parameter(encoding, parm);
  2071.             }
  2072.             octstr_destroy(value_encoding);
  2073.         }
  2074.         pack_value(packed, encoding);
  2075.         octstr_destroy(encoding);
  2076.     }
  2077.     parm_destroy(parm);
  2078.     return 1;
  2079. }
  2080. static int pack_content_disposition(Octstr *packed, Octstr *value)
  2081. {
  2082.     List *parms;
  2083.     long disposition;
  2084.     parms = strip_parameters(value);
  2085.     disposition = wsp_string_to_disposition(value);
  2086.     if (disposition >= 0) {
  2087.         Octstr *encoding = octstr_create("");
  2088.         pack_short_integer(encoding, disposition);
  2089.         pack_parameters(encoding, parms);
  2090.         pack_value(packed, encoding);
  2091.         octstr_destroy(encoding);
  2092.     } else {
  2093.         warning(0, "WSP: Cannot encode Content-Disposition '%s'.",
  2094.                 octstr_get_cstr(value));
  2095.         goto error;
  2096.     }
  2097.     list_destroy(parms, parm_destroy_item);
  2098.     return 0;
  2099. error:
  2100.     list_destroy(parms, parm_destroy_item);
  2101.     return -1;
  2102. }
  2103. static int pack_content_range(Octstr *packed, Octstr *value)
  2104. {
  2105.     Octstr *bytes;
  2106.     long pos;
  2107.     long firstbyte, lastbyte, instancelen;
  2108.     Octstr *encoding;
  2109.     bytes = octstr_imm("bytes ");
  2110.     if (octstr_ncompare(value, bytes, octstr_len(bytes)) != 0)
  2111.         goto error;
  2112.     pos = octstr_len(bytes);
  2113.     while (isspace(octstr_get_char(value, pos)))
  2114.         pos++;
  2115.     if (octstr_get_char(value, pos) == '*')
  2116.         goto warning;
  2117.     pos = octstr_parse_long(&firstbyte, value, pos, 10);
  2118.     if (pos < 0)
  2119.         goto error;
  2120.     while (isspace(octstr_get_char(value, pos)))
  2121.         pos++;
  2122.     if (octstr_get_char(value, pos++) != '-')
  2123.         goto error;
  2124.     pos = octstr_parse_long(&lastbyte, value, pos, 10);
  2125.     if (pos < 0)
  2126.         goto error;
  2127.     while (isspace(octstr_get_char(value, pos)))
  2128.         pos++;
  2129.     if (octstr_get_char(value, pos++) != '/')
  2130.         goto error;
  2131.     while (isspace(octstr_get_char(value, pos)))
  2132.         pos++;
  2133.     if (octstr_get_char(value, pos) == '*')
  2134.         goto warning;
  2135.     pos = octstr_parse_long(&instancelen, value, pos, 10);
  2136.     if (pos < 0)
  2137.         goto error;
  2138.     /* XXX: If the range is valid but not representable,
  2139.      * or if it's invalid, then should we refrain from sending
  2140.      * anything at all?  It might pollute the client's cache. */
  2141.     if (lastbyte < firstbyte || instancelen < lastbyte) {
  2142.         warning(0, "WSP: Content-Range '%s' is invalid.",
  2143.                 octstr_get_cstr(value));
  2144.         return -1;
  2145.     }
  2146.     encoding = octstr_create("");
  2147.     octstr_append_uintvar(encoding, firstbyte);
  2148.     octstr_append_uintvar(encoding, instancelen);
  2149.     pack_value(packed, encoding);
  2150.     octstr_destroy(encoding);
  2151.     return 0;
  2152. error:
  2153.     warning(0, "WSP: Cannot parse Content-Range '%s'.",
  2154.             octstr_get_cstr(value));
  2155.     return -1;
  2156. warning:
  2157.     warning(0, "WSP: Cannot encode Content-Range '%s'.",
  2158.             octstr_get_cstr(value));
  2159.     return -1;
  2160. }
  2161. static int pack_content_type(Octstr *packed, Octstr *value)
  2162. {
  2163.     /* The expansion of Content-type-value works out to be
  2164.      * equivalent to Accept-value. */ 
  2165.     return pack_accept(packed, value);
  2166. }
  2167. static int pack_expires(Octstr *packed, Octstr *value)
  2168. {
  2169.     int ret;
  2170.     ret = pack_date(packed, value);
  2171.     if (ret < 0) {
  2172. /* Responses with an invalid Expires header should be treated
  2173. as already expired.  If we just skip this header, then the client
  2174. won't know that.  So we encode one with a date far in the past. */
  2175. pack_long_integer(packed, LONG_AGO_VALUE);
  2176. ret = 0;
  2177.     }
  2178.     return ret;
  2179. }
  2180. static int pack_if_range(Octstr *packed, Octstr *value)
  2181. {
  2182.     if (octstr_get_char(value, 0) == '"' ||
  2183.         (octstr_get_char(value, 0) == 'W' &&
  2184.          octstr_get_char(value, 1) == '/')) {
  2185.         return pack_text(packed, value);   /* It's an etag */
  2186.     } else {
  2187.         return pack_date(packed, value);
  2188.     }
  2189. }
  2190. static int pack_pragma(Octstr *packed, Octstr *value)
  2191. {
  2192.     Octstr *nocache;
  2193.     nocache = octstr_imm("no-cache");
  2194.     if (octstr_case_compare(value, nocache) == 0)
  2195.         pack_short_integer(packed, WSP_CACHE_CONTROL_NO_CACHE);
  2196.     else {
  2197.         Parameter *parm;
  2198.         Octstr *encoding;
  2199.         encoding = octstr_create("");
  2200.         parm = parm_parse(value);
  2201.         pack_parameter(encoding, parm);
  2202.         pack_value(packed, encoding);
  2203.         octstr_destroy(encoding);
  2204.         parm_destroy(parm);
  2205.     }
  2206.     return 0;
  2207. }
  2208. static int pack_range(Octstr *packed, Octstr *value)
  2209. {
  2210.     Octstr *bytes = octstr_imm("bytes");
  2211.     long pos;
  2212.     if (octstr_ncompare(value, bytes, octstr_len(bytes)) != 0
  2213.         || is_token_char(octstr_get_char(value, octstr_len(bytes))))
  2214.         goto error;
  2215.     pos = octstr_len(bytes);
  2216.     while (isspace(octstr_get_char(value, pos)))
  2217.         pos++;
  2218.     if (octstr_get_char(value, pos) != '=')
  2219.         goto error;
  2220.     pos++;
  2221.     for (;;) {
  2222.         /* Discard the whole header if any part of it can't be
  2223.          * parsed.  Probably a partial Range header is worse
  2224.          * than none at all. */
  2225.         pos = pack_range_value(packed, value, pos);
  2226.         if (pos < 0)
  2227.             goto error;
  2228.         while (isspace(octstr_get_char(value, pos)))
  2229.             pos++;
  2230.         if (octstr_get_char(value, pos) != ',')
  2231.             break;
  2232.         pos++;
  2233.         pack_short_integer(packed, WSP_HEADER_RANGE);
  2234.     }
  2235.     return 0;
  2236. error:
  2237.     warning(0, "WSP: Cannot parse 'Range: %s'.",
  2238.             octstr_get_cstr(value));
  2239.     return -1;
  2240. }
  2241. /* The value is either a HTTP-date or a delta-seconds (integer). */
  2242. static int pack_retry_after(Octstr *packed, Octstr *value)
  2243. {
  2244.     Octstr *encoded = NULL;
  2245.     encoded = octstr_create("");
  2246.     if (isdigit(octstr_get_char(value, 0))) {
  2247.         octstr_append_char(encoded, RELATIVE_TIME);
  2248.         if (pack_integer_string(encoded, value) < 0)
  2249.             goto error;
  2250.     } else {
  2251.         octstr_append_char(encoded, ABSOLUTE_TIME);
  2252.         if (pack_date(encoded, value) < 0)
  2253.             goto error;
  2254.     }
  2255.     pack_value(packed, encoded);
  2256.     octstr_destroy(encoded);
  2257.     return 0;
  2258. error:
  2259.     octstr_destroy(encoded);
  2260.     return -1;
  2261. }
  2262. static int convert_rfc2616_warning_to_rfc2068(int warn_code)
  2263. {
  2264.     int i;
  2265.     struct {
  2266. int rfc2616code;
  2267. int rfc2068code;
  2268.     } code_transform[] = {
  2269. { 110, 10 },  /* Response is stale */
  2270. { 111, 11 },  /* Revalidation failed */
  2271. { 112, 12 },  /* Disconnected operation */
  2272. { 113, 13 },  /* Heuristic expiration */
  2273. { 199, 99 },  /* Miscellaneous warning */
  2274. { 214, 14 },  /* Transformation applied */
  2275. { 299, 99 },  /* Miscellaneous (persistent) warning */
  2276. { -1, -1 }
  2277.     };
  2278.     
  2279.     for (i = 0; code_transform[i].rfc2616code >= 0; i++) {
  2280. if (code_transform[i].rfc2616code == warn_code)
  2281.     return code_transform[i].rfc2068code;
  2282.     }
  2283.     return warn_code; /* conversion failed */
  2284. }
  2285. static int pack_warning(Octstr *packed, Octstr *value)
  2286. {
  2287.     long warn_code = -1;
  2288.     Octstr *warn_agent = NULL;
  2289.     Octstr *warn_text = NULL;
  2290.     long pos;
  2291.     long start;
  2292.     pos = octstr_parse_long(&warn_code, value, 0, 10);
  2293.     if (pos < 0 || warn_code < 0)
  2294.         goto error;
  2295.     if (warn_code > 99) {
  2296. /* RFC2068 uses 2-digit codes, and RFC2616 uses 3-digit codes.
  2297.  * This must be an RFC2616 code.  We don't have room in the
  2298.  * encoding for such codes, so we try to convert it back to
  2299.  * an RFC2068 code. */
  2300. warn_code = convert_rfc2616_warning_to_rfc2068(warn_code);
  2301.     }
  2302.     if (warn_code > MAX_SHORT_INTEGER) {
  2303. warning(0, "WSP: Cannot encode warning code %ld.", warn_code);
  2304. return -1;
  2305.     }
  2306.     while (isspace(octstr_get_char(value, pos)))
  2307.         pos++;
  2308.     start = pos;
  2309.     while (pos < octstr_len(value) && !isspace(octstr_get_char(value, pos)))
  2310.         pos++;
  2311.     if (pos > start)
  2312.         warn_agent = octstr_copy(value, start, pos - start);
  2313.     while (isspace(octstr_get_char(value, pos)))
  2314.         pos++;
  2315.     start = pos;
  2316.     pos += http_header_quoted_string_len(value, pos);
  2317.     if (pos > start)
  2318.         warn_text = octstr_copy(value, start, pos - start);
  2319.     if (warn_agent == NULL && warn_text == NULL) {
  2320.         /* Simple encoding */
  2321.         pack_short_integer(packed, warn_code);
  2322.     } else {
  2323.         /* General encoding */
  2324.         Octstr *encoding = octstr_create("");
  2325.         if (warn_agent == NULL)
  2326.             warn_agent = octstr_create("");
  2327.         if (warn_text == NULL)
  2328.             warn_text = octstr_create("");
  2329. pack_short_integer(encoding, warn_code);
  2330.         pack_text(encoding, warn_agent);
  2331.         pack_text(encoding, warn_text);
  2332.         pack_value(packed, encoding);
  2333.         octstr_destroy(encoding);
  2334.     }
  2335.     octstr_destroy(warn_agent);
  2336.     octstr_destroy(warn_text);
  2337.     return 0;
  2338. error:
  2339.     warning(0, "WSP: Cannot parse 'Warning: %s'.",
  2340.             octstr_get_cstr(value));
  2341.     octstr_destroy(warn_agent);
  2342.     octstr_destroy(warn_text);
  2343.     return -1;
  2344. }
  2345. static void pack_separate_content_type(Octstr *packed, List *headers)
  2346. {
  2347.     Octstr *content_type;
  2348.     /* Can't use http_header_get_content_type because it
  2349.      * does not parse all possible parameters. */
  2350.     content_type = http_header_find_first(headers, "Content-Type");
  2351.     if (content_type == NULL) {
  2352.         warning(0, "WSP: Missing Content-Type header in "
  2353.                 "response, guessing application/octet-stream");
  2354.         content_type = octstr_create("application/octet-stream");
  2355.     }
  2356.     octstr_strip_blanks(content_type);
  2357.     pack_content_type(packed, content_type);
  2358.     octstr_destroy(content_type);
  2359. }
  2360. static int pack_list(Octstr *packed, long fieldnum, List *elements, int i)
  2361. {
  2362.     long startpos;
  2363.     Octstr *element;
  2364.     while ((element = list_consume(elements))) {
  2365.         startpos = octstr_len(packed);
  2366.         pack_short_integer(packed, fieldnum);
  2367.         if (headerinfo[i].func(packed, element) < 0) {
  2368.             /* Remove whatever we added */
  2369.             octstr_delete(packed, startpos,
  2370.                           octstr_len(packed) - startpos);
  2371.             /* But continue processing elements */
  2372.         }
  2373.         octstr_destroy(element);
  2374.     }
  2375.     return 0;
  2376. }
  2377. static int pack_known_header(Octstr *packed, long fieldnum, Octstr *value)
  2378. {
  2379.     List *elements = NULL;
  2380.     long startpos;
  2381.     long i;
  2382.     octstr_strip_blanks(value);
  2383.     startpos = octstr_len(packed);
  2384.     for (i = 0; i < TABLE_SIZE(headerinfo); i++) {
  2385.         if (headerinfo[i].header == fieldnum)
  2386.             break;
  2387.     }
  2388.     if (i == TABLE_SIZE(headerinfo)) {
  2389.         error(0, "WSP: Do not know how to encode header type %ld",
  2390.               fieldnum);
  2391.         goto error;
  2392.     }
  2393.     if (headerinfo[i].allows_list == LIST)
  2394.         elements = http_header_split_value(value);
  2395.     else if (headerinfo[i].allows_list == BROKEN_LIST)
  2396.         elements = http_header_split_auth_value(value);
  2397.     else
  2398.         elements = NULL;
  2399.     if (elements != NULL) {
  2400.         if (pack_list(packed, fieldnum, elements, i) < 0)
  2401.             goto error;
  2402.     } else {
  2403.         pack_short_integer(packed, fieldnum);
  2404.         if (headerinfo[i].func(packed, value) < 0)
  2405.             goto error;
  2406.     }
  2407.     list_destroy(elements, octstr_destroy_item);
  2408.     return 0;
  2409. error:
  2410.     /* Remove whatever we added */
  2411.     octstr_delete(packed, startpos, octstr_len(packed) - startpos);
  2412.     list_destroy(elements, octstr_destroy_item);
  2413.     return -1;
  2414. }
  2415. static int pack_application_header(Octstr *packed,
  2416.                                    Octstr *fieldname, Octstr *value)
  2417. {
  2418.     if (!is_token(fieldname)) {
  2419.         warning(0, "WSP headers: `%s' is not a valid HTTP token.",
  2420.                 octstr_get_cstr(fieldname));
  2421.         return -1;
  2422.     }
  2423.     /* We have to deal specially with the X-WAP.TOD header, because it
  2424.      * is the only case of a text-format header defined with a non-text
  2425.      * field value. */
  2426.     /* Normally this should be a case-insensitive comparison, but this
  2427.      * header will only be present if we generated it ourselves in the
  2428.      * application layer. */
  2429.     if (octstr_str_compare(fieldname, "X-WAP.TOD") == 0) {
  2430. pack_text(packed, fieldname);
  2431. return pack_date(packed, value);
  2432.     }
  2433.     pack_text(packed, fieldname);
  2434.     pack_text(packed, value);
  2435.     return 0;
  2436. }
  2437. Octstr *wsp_headers_pack(List *headers, int separate_content_type)
  2438. {
  2439.     Octstr *packed;
  2440.     long i, len;
  2441.     int errors;
  2442.     packed = octstr_create("");
  2443.     if (separate_content_type)
  2444.         pack_separate_content_type(packed, headers);
  2445.     len = list_len(headers);
  2446.     for (i = 0; i < len; i++) {
  2447.         Octstr *fieldname;
  2448.         Octstr *value;
  2449.         long fieldnum;
  2450.         http_header_get(headers, i, &fieldname, &value);
  2451.         fieldnum = wsp_string_to_header(fieldname);
  2452.         errors = 0;
  2453.         if (separate_content_type && fieldnum == WSP_HEADER_CONTENT_TYPE) {
  2454.     /* already handled */
  2455.         } else if (fieldnum < 0) {
  2456.             if (pack_application_header(packed, fieldname, value) < 0)
  2457.                 errors = 1;
  2458.         } else {
  2459.             if (pack_known_header(packed, fieldnum, value) < 0)
  2460.                 errors = 1;
  2461.         }
  2462.         if (errors)
  2463.             warning(0, "Skipping header: %s: %s",
  2464.                     octstr_get_cstr(fieldname),
  2465.                     octstr_get_cstr(value));
  2466.         octstr_destroy(fieldname);
  2467.         octstr_destroy(value);
  2468.     }
  2469.     return packed;
  2470. }