Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
wsp_headers.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * wsp_headers.c - Implement WSP PDU headers
59  *
60  * References:
61  * WSP specification version 1.1
62  * RFC 2068, Hypertext Transfer Protocol HTTP/1.1
63  * RFC 2616, Hypertext Transfer Protocol HTTP/1.1
64  *
65  * For push headers, WSP specification, June 2000 conformance release
66  *
67  * This file has two parts. The first part decodes the request's headers
68  * from WSP to HTTP. The second part encodes the response's headers from
69  * HTTP to WSP.
70  *
71  * Note that push header encoding and decoding are divided two parts:
72  * first decoding and encoding numeric values and then packing these values
73  * into WSP format and unpacking them from WSP format. This module contains
74  * only packing and unpacking parts.
75  *
76  * Some functions are declared non-static to provide them for external use,
77  * ie. the MMS encapsulation encoding and decoding routines implemented in
78  * other files.
79  *
80  * Richard Braakman
81  * Stipe Tolj <stolj@wapme.de>
82  */
83 
84 #include <string.h>
85 #include <limits.h>
86 #include <ctype.h>
87 
88 #include "gwlib/gwlib.h"
89 #include "wsp.h"
90 #include "wsp_headers.h"
91 #include "wsp_strings.h"
92 
93 /*
94  * get field value and return its type as predefined data types
95  * There are three kinds of field encodings:
96  * WSP_FIELD_VALUE_NUL_STRING: 0-terminated string
97  * WSP_FIELD_VALUE_ENCODED: short integer, range 0-127
98  * WSP_FIELD_VALUE_DATA: octet string defined by length
99  * The function will return one of those values, and modify the parse context
100  * to make it easy to get the field data.
101  * WSP_FIELD_VALUE_NUL_STRING: Leave parsing position at start of string
102  * WSP_FIELD_VALUE_ENCODED: Put value in *well_known_value, leave
103  * parsing position after field value.
104  * WSP_FIELD_VALUE_DATA: Leave parsing position at start of data, and set
105  * a parse limit at the end of data.
106  */
107 int wsp_field_value(ParseContext *context, int *well_known_value)
108 {
109  int val;
110  unsigned long len;
111 
112  val = parse_get_char(context);
113  if (val > 0 && val < 31) {
114  *well_known_value = -1;
115  parse_limit(context, val);
116  return WSP_FIELD_VALUE_DATA;
117  } else if (val == 31) {
118  *well_known_value = -1;
119  len = parse_get_uintvar(context);
120  parse_limit(context, len);
121  return WSP_FIELD_VALUE_DATA;
122  } else if (val > 127) {
123  *well_known_value = val - 128;
125  } else if (val == WSP_QUOTE || val == '"') { /* 127 */
126  *well_known_value = -1;
127  /* We already consumed the Quote */
129  } else { /* implicite val == 0 */
130  *well_known_value = -1;
131  /* Un-parse the character we just read */
132  parse_skip(context, -1);
134  }
135 }
136 
137 /* Skip over a field_value as defined above. */
139 {
140  int val;
141  int ret;
142 
143  ret = wsp_field_value(context, &val);
144  if (ret == WSP_FIELD_VALUE_DATA) {
145  parse_skip_to_limit(context);
146  parse_pop_limit(context);
147  }
148 }
149 
150 /* Multi-octet-integer is defined in 8.4.2.1 */
152 {
153  long val = 0;
154 
155  if (len > (long) sizeof(val) || len < 0)
156  return -1;
157 
158  while (len > 0) {
159  val = val * 256 + parse_get_char(context);
160  len--;
161  }
162 
163  if (parse_error(context))
164  return -1;
165 
166  return val;
167 }
168 
169 /* This function is similar to field_value, but it is used at various
170  * places in the grammar where we expect either an Integer-value
171  * or some kind of NUL-terminated text.
172  *
173  * Return values are just like field_value except that WSP_FIELD_VALUE_DATA
174  * will not be returned.
175  *
176  * As a special case, we parse a 0-length Long-integer as an
177  * WSP_FIELD_VALUE_NONE, so that we can distinguish between No-value
178  * and an Integer-value of 0. (A real integer 0 would be encoded as
179  * a Short-integer; the definition of Long-integer seems to allow
180  * 0-length integers, but the definition of Multi-octet-integer does
181  * not, so this is an unclear area of the specification.)
182  */
184 {
185  int val;
186  long length;
187 
188  val = parse_get_char(context);
189  if (val == 0) {
190  *result = 0;
191  return WSP_FIELD_VALUE_NONE;
192  } else if (val > 0 && val < 31) {
193  *result = unpack_multi_octet_integer(context, val);
195  } else if (val == 31) {
196  length = parse_get_uintvar(context);
197  *result = unpack_multi_octet_integer(context, length);
199  } else if (val > 127) {
200  *result = val - 128;
202  } else if (val == WSP_QUOTE) { /* 127 */
203  *result = -1;
205  } else {
206  *result = -1;
207  /* Un-parse the character we just read */
208  parse_skip(context, -1);
210  }
211 }
212 
213 /* Integer-value is defined in 8.4.2.3 */
215 {
216  Octstr *decoded;
217  unsigned long value;
218  int val;
219 
220  val = parse_get_char(context);
221  if (val < 31) {
222  value = unpack_multi_octet_integer(context, val);
223  } else if (val > 127) {
224  value = val - 128;
225  } else {
226  warning(0, "WSP headers: bad integer-value.");
227  return NULL;
228  }
229 
230  decoded = octstr_create("");
231  octstr_append_decimal(decoded, value);
232  return decoded;
233 }
234 
235 /* Q-value is defined in 8.4.2.3 */
236 static Octstr *convert_q_value(int q)
237 {
238  Octstr *result = NULL;
239 
240  /* When quality factor 0 and quality factors with one or two
241  * decimal digits are encoded, they shall be multiplied by 100
242  * and incremented by one, so that they encode as a one-octet
243  * value in range 1-100. */
244  if (q >= 1 && q <= 100) {
245  q = q - 1;
246  result = octstr_create("0.");
247  octstr_append_char(result, (q / 10) + '0');
248  if (q % 10 > 0)
249  octstr_append_char(result, (q % 10) + '0');
250  return result;
251  }
252 
253  /* Three decimal quality factors shall be multiplied with 1000
254  * and incremented by 100. */
255  if (q > 100 && q <= 1000) {
256  q = q - 100;
257  result = octstr_create("0.");
258  octstr_append_char(result, (q / 100) + '0');
259  if (q % 100 > 0)
260  octstr_append_char(result, (q / 10 % 10) + '0');
261  if (q % 10 > 0)
262  octstr_append_char(result, (q % 10) + '0');
263  return result;
264  }
265 
266  return NULL;
267 }
268 
269 /* Q-value is defined in 8.4.2.3 */
271 {
272  int c, c2;
273 
274  c = parse_get_char(context);
275  if (c < 0)
276  return NULL;
277 
278  if (c & 0x80) {
279  c2 = parse_get_char(context);
280  if (c2 < 0 || (c2 & 0x80))
281  return NULL;
282  c = ((c & 0x7f) << 8) + c2;
283  }
284 
285  return convert_q_value(c);
286 }
287 
288 
289 /* Version-value is defined in 8.4.2.3. Encoding-Version uses coding
290  * defined in this chapter, see 8.4.2.70. */
292 {
293  Octstr *result;
294  int major, minor;
295 
296  major = ((value >> 4) & 0x7);
297  minor = (value & 0xf);
298 
299  result = octstr_create("");
300  octstr_append_char(result, major + '0');
301  if (minor != 15) {
302  octstr_append_char(result, '.');
303  octstr_append_decimal(result, minor);
304  }
305 
306  return result;
307 }
308 
310 {
311  int ch;
312 
313  ch = parse_get_char(context);
314  if (ch < 128) {
315  warning(0, "WSP: bad Encoding-Version value");
316  return NULL;
317  }
318 
319  return wsp_unpack_version_value(((long) ch) - 128);
320 }
321 
322 
323 /* Called with the parse limit set to the end of the parameter data,
324  * and decoded containing the unpacked header line so far.
325  * Parameter is defined in 8.4.2.4. */
327 {
328  Octstr *parm = NULL;
329  Octstr *value = NULL;
330  int ret;
331  long type;
332  long val;
333 
334  ret = wsp_secondary_field_value(context, &type);
335  if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
336  warning(0, "bad parameter");
337  goto error;
338  }
339 
340  if (ret == WSP_FIELD_VALUE_ENCODED) {
341  /* Typed-parameter */
342  parm = wsp_parameter_to_string(type);
343  if (!parm)
344  warning(0, "Unknown parameter %02lx.", type);
345  } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
346  /* Untyped-parameter */
347  parm = parse_get_nul_string(context);
348  if (!parm)
349  warning(0, "Format error in parameter.");
350  type = -1;
351  /* We treat Untyped-value as a special type. Its format
352  * Integer-value | Text-value is pretty similar to most
353  * typed formats. */
354  } else {
355  panic(0, "Unknown secondary field value type %d.", ret);
356  }
357 
358  if (type == 0x00) /* q */
359  value = unpack_q_value(context);
360  else {
361  ret = wsp_secondary_field_value(context, &val);
362  if (parse_error(context)) {
363  warning(0, "bad parameter value");
364  goto error;
365  }
366 
367  if (ret == WSP_FIELD_VALUE_ENCODED) {
368  switch (type) {
369  case -1: /* untyped: Integer-value */
370  case 3: /* type: Integer-value */
371  case 8: /* padding: Short-integer */
372  value = octstr_create("");
373  octstr_append_decimal(value, val);
374  break;
375  case 0: /* q, already handled above */
376  gw_assert(0);
377  break;
378  case 1: /* charset: Well-known-charset */
379  value = wsp_charset_to_string(val);
380  if (!value)
381  warning(0, "Unknown charset %04lx.", val);
382  break;
383  case 2: /* level: Version-value */
384  value = wsp_unpack_version_value(val);
385  break;
386  case 5: /* name: Text-string */
387  case 6: /* filename: Text-string */
388  warning(0, "Text-string parameter with integer encoding");
389  break;
390  case 7: /* differences: Field-name */
391  value = wsp_header_to_string(val);
392  if (!value)
393  warning(0, "Unknown differences header %02lx.", val);
394  break;
395  default:
396  warning(0, "Unknown parameter encoding %02lx.",
397  type);
398  break;
399  }
400  } else if (ret == WSP_FIELD_VALUE_NONE) {
401  value = octstr_create("");
402  } else {
404  /* Text-value = No-value | Token-text | Quoted-string */
405  value = parse_get_nul_string(context);
406  if (!value)
407  warning(0, "Format error in parameter value.");
408  else {
409  if (octstr_get_char(value, 0) == '"') {
410  /* Quoted-string */
411  octstr_append_char(value, '"');
412  } else { /* DAVI! */
413  octstr_insert(value, octstr_imm("\""), 0);
414  octstr_append_char(value, '"');
415  }
416  }
417  }
418  }
419 
420  if (!parm || !value) {
421  warning(0, "Skipping parameters");
422  goto error;
423  }
424 
425  octstr_append(decoded, octstr_imm("; "));
426  octstr_append(decoded, parm);
427  if (octstr_len(value) > 0) {
428  octstr_append_char(decoded, '=');
429  octstr_append(decoded, value);
430  }
431  octstr_destroy(parm);
432  octstr_destroy(value);
433  return 0;
434 
435 error:
436  parse_skip_to_limit(context);
437  octstr_destroy(parm);
438  octstr_destroy(value);
439  parse_set_error(context);
440  return -1;
441 }
442 
444 {
445  int ret = 0;
446 
447  while (ret >= 0 && !parse_error(context) &&
448  parse_octets_left(context) > 0) {
449  ret = unpack_parameter(context, decoded);
450  }
451 }
452 
453 /* Unpack parameters in the format used by credentials and challenge,
454  * which differs from the format used by all other HTTP headers. */
456 {
457  int ret = 0;
458  int first = 1;
459  long pos;
460 
461  while (ret >= 0 && !parse_error(context) &&
462  parse_octets_left(context) > 0) {
463  pos = octstr_len(decoded);
464  ret = unpack_parameter(context, decoded);
465  if (ret >= 0) {
466  if (first) {
467  /* Zap ';' */
468  octstr_delete(decoded, pos, 1);
469  first = 0;
470  } else {
471  /* Replace ';' with ',' */
472  octstr_set_char(decoded, pos, first ? ' ' : ',');
473  }
474  }
475  }
476 }
477 
479 {
480  if (parse_octets_left(context) > 0) {
481  Octstr *qval = unpack_q_value(context);
482  if (qval) {
483  octstr_append(decoded, octstr_imm("; q="));
484  octstr_append(decoded, qval);
485  octstr_destroy(qval);
486  } else
487  warning(0, "Bad q-value");
488  }
489 }
490 
491 /* Date-value is defined in 8.4.2.3. */
493 {
494  unsigned long timeval;
495  int length;
496 
497  length = parse_get_char(context);
498  if (length > 30) {
499  warning(0, "WSP headers: bad date-value.");
500  return NULL;
501  }
502 
503  timeval = unpack_multi_octet_integer(context, length);
504  if (timeval < 0) {
505  warning(0, "WSP headers: cannot unpack date-value.");
506  return NULL;
507  }
508 
509  return date_format_http(timeval);
510 }
511 
512 /* Accept-general-form is defined in 8.4.2.7 */
514 {
515  Octstr *decoded = NULL;
516  int ret;
517  long val;
518 
519  /* The definition for Accept-general-form looks quite complicated,
520  * but the "Q-token Q-value" part fits the normal expansion of
521  * Parameter, so it simplifies to:
522  * Value-length Media-range *(Parameter)
523  * and we've already parsed Value-length.
524  */
525 
526  /* We use this function to parse content-general-form too,
527  * because its definition of Media-type is identical to Media-range.
528  */
529 
530  ret = wsp_secondary_field_value(context, &val);
531  if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
532  warning(0, "bad media-range or media-type");
533  return NULL;
534  }
535 
536  if (ret == WSP_FIELD_VALUE_ENCODED) {
537  decoded = wsp_content_type_to_string(val);
538  if (!decoded) {
539  warning(0, "Unknown content type 0x%02lx.", val);
540  return NULL;
541  }
542  } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
543  decoded = parse_get_nul_string(context);
544  if (!decoded) {
545  warning(0, "Format error in content type");
546  return NULL;
547  }
548  } else {
549  panic(0, "Unknown secondary field value type %d.", ret);
550  }
551 
552  wsp_unpack_all_parameters(context, decoded);
553  return decoded;
554 }
555 
556 /* Accept-charset-general-form is defined in 8.4.2.8 */
558 {
559  Octstr *decoded = NULL;
560  int ret;
561  long val;
562 
563  ret = wsp_secondary_field_value(context, &val);
564  if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
565  warning(0, "Bad accept-charset-general-form");
566  return NULL;
567  }
568 
569  if (ret == WSP_FIELD_VALUE_ENCODED) {
570  decoded = wsp_charset_to_string(val);
571  if (!decoded) {
572  warning(0, "Unknown character set %04lx.", val);
573  return NULL;
574  }
575  } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
576  decoded = parse_get_nul_string(context);
577  if (!decoded) {
578  warning(0, "Format error in accept-charset");
579  return NULL;
580  }
581  } else {
582  panic(0, "Unknown secondary field value type %d.", ret);
583  }
584 
585  unpack_optional_q_value(context, decoded);
586  return decoded;
587 }
588 
589 /* Accept-language-general-form is defined in 8.4.2.10 */
591 {
592  Octstr *decoded = NULL;
593  int ret;
594  long val;
595 
596  ret = wsp_secondary_field_value(context, &val);
597  if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
598  warning(0, "Bad accept-language-general-form");
599  return NULL;
600  }
601 
602  if (ret == WSP_FIELD_VALUE_ENCODED) {
603  /* Any-language is handled by a special entry in the
604  * language table. */
605  decoded = wsp_language_to_string(val);
606  if (!decoded) {
607  warning(0, "Unknown language %02lx.", val);
608  return NULL;
609  }
610  } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
611  decoded = parse_get_nul_string(context);
612  if (!decoded) {
613  warning(0, "Format error in accept-language");
614  return NULL;
615  }
616  } else {
617  panic(0, "Unknown secondary field value type %d.", ret);
618  }
619 
620  unpack_optional_q_value(context, decoded);
621  return decoded;
622 }
623 
624 /* Credentials is defined in 8.4.2.5 */
626 {
627  Octstr *decoded = NULL;
628  int val;
629 
630  val = parse_peek_char(context);
631 
632  if (val == BASIC_AUTHENTICATION) {
633  Octstr *userid, *password;
634 
635  parse_skip(context, 1);
636 
637  userid = parse_get_nul_string(context);
638  password = parse_get_nul_string(context);
639 
640  if (parse_error(context)) {
641  octstr_destroy(userid);
642  octstr_destroy(password);
643  } else {
644  /* Create the user-pass cookie */
645  decoded = octstr_duplicate(userid);
646  octstr_append_char(decoded, ':');
647  octstr_append(decoded, password);
648 
649  /* XXX Deal with cookies that overflow the 76-per-line
650  * limit of base64. Either go through and zap all
651  * CR LF sequences, or give the conversion function
652  * a flag or something to leave them out. */
653  octstr_binary_to_base64(decoded);
654 
655  /* Zap the CR LF at the end */
656  octstr_delete(decoded, octstr_len(decoded) - 2, 2);
657 
658  octstr_insert_data(decoded, 0, "Basic ", 6);
659 
660  octstr_destroy(userid);
661  octstr_destroy(password);
662  }
663  } else if (val >= 32 && val < 128) {
664  /* Generic authentication scheme */
665  decoded = parse_get_nul_string(context);
666  if (decoded)
667  unpack_broken_parameters(context, decoded);
668  }
669 
670  if (!decoded)
671  warning(0, "Cannot parse credentials.");
672 
673  return decoded;
674 }
675 
676 /* Credentials is defined in 8.4.2.5
677  * but as Proxy-Authentication is to be used by kannel,
678  * a simplier to parse version is used here */
680 {
681  Octstr *decoded = NULL;
682  int val;
683 
684  val = parse_peek_char(context);
685 
686  if (val == BASIC_AUTHENTICATION) {
687  Octstr *userid, *password;
688 
689  parse_skip(context, 1);
690 
691  userid = parse_get_nul_string(context);
692  password = parse_get_nul_string(context);
693 
694  if (parse_error(context)) {
695  octstr_destroy(userid);
696  octstr_destroy(password);
697  } else {
698  /* Create the user-pass cookie */
699  decoded = octstr_duplicate(userid);
700  octstr_append_char(decoded, ':');
701  octstr_append(decoded, password);
702  octstr_destroy(userid);
703  octstr_destroy(password);
704  }
705  } else if (val >= 32 && val < 128) {
706  /* Generic authentication scheme */
707  decoded = parse_get_nul_string(context);
708  if (decoded)
709  unpack_broken_parameters(context, decoded);
710  }
711 
712  if (!decoded)
713  warning(0, "Cannot parse credentials.");
714 
715  return decoded;
716 }
717 
718 /* Challenge is defined in 8.4.2.5 */
720 {
721  Octstr *decoded = NULL;
722  Octstr *realm_value = NULL;
723  int val;
724 
725  val = parse_peek_char(context);
726  if (val == BASIC_AUTHENTICATION) {
727  parse_skip(context, 1);
728  realm_value = parse_get_nul_string(context);
729  if (realm_value) {
730  decoded = octstr_create("Basic realm=\"");
731  octstr_append(decoded, realm_value);
732  octstr_append_char(decoded, '"');
733  }
734  } else if (val >= 32 && val < 128) {
735  /* Generic authentication scheme */
736  decoded = parse_get_nul_string(context);
737  realm_value = parse_get_nul_string(context);
738  if (decoded && realm_value) {
739  octstr_append(decoded,
740  octstr_imm(" realm=\""));
741  octstr_append(decoded, realm_value);
742  octstr_append_char(decoded, '"');
743  if (parse_octets_left(context) > 0) {
744  /* Prepare for following parameter list */
745  octstr_append_char(decoded, ',');
746  }
747  unpack_broken_parameters(context, decoded);
748  }
749  }
750 
751  if (!decoded)
752  warning(0, "Cannot parse challenge.");
753 
754  octstr_destroy(realm_value);
755  return decoded;
756 }
757 
758 /* Content-range is defined in 8.4.2.23 */
760 {
761  /* We'd have to figure out how to access the content range
762  * length (i.e. user_data size) from here to parse this,
763  * and I don't see why the _client_ would send this in any case. */
764  warning(0, "Decoding of content-range not supported");
765  return NULL;
766 
767  /*
768  Octstr *decoded = NULL;
769  unsigned long first_byte_pos, entity_length;
770  unsigned long last_byte_pos;
771 
772  first_byte_pos = parse_get_uintvar(context);
773  entity_length = parse_get_uintvar(context);
774 
775  if (parse_error(context)) {
776  warning(0, "Cannot parse content-range header");
777  return NULL;
778  }
779 
780  decoded = octstr_create("bytes ");
781  octstr_append_decimal(decoded, first_byte_pos);
782  octstr_append_char(decoded, '-');
783  octstr_append_decimal(decoded, last_byte_pos);
784  octstr_append_char(decoded, '/');
785  octstr_append_decimal(decoded, entity_length);
786 
787  return decoded;
788  */
789 }
790 
791 /* Field-name is defined in 8.4.2.6 */
793 {
794  Octstr *decoded = NULL;
795  int ret;
796  int val;
797 
798  ret = wsp_field_value(context, &val);
799  if (parse_error(context) || ret == WSP_FIELD_VALUE_DATA) {
800  warning(0, "Bad field-name encoding");
801  return NULL;
802  }
803 
804  if (ret == WSP_FIELD_VALUE_ENCODED) {
805  decoded = wsp_header_to_string(val);
806  if (!decoded) {
807  warning(0, "Unknown field-name 0x%02x.", val);
808  return NULL;
809  }
810  } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
811  decoded = parse_get_nul_string(context);
812  if (!decoded) {
813  warning(0, "Bad field-name encoding");
814  return NULL;
815  }
816  } else {
817  panic(0, "Unknown field value type %d.", ret);
818  }
819 
820  return decoded;
821 }
822 
823 /* Cache-directive is defined in 8.4.2.15 */
825 {
826  Octstr *decoded = NULL;
827  int ret;
828  int val;
829 
830  ret = wsp_field_value(context, &val);
831  if (parse_error(context) || ret == WSP_FIELD_VALUE_DATA) {
832  warning(0, "Bad cache-directive");
833  goto error;
834  }
835 
836  if (ret == WSP_FIELD_VALUE_ENCODED) {
837  decoded = wsp_cache_control_to_string(val);
838  if (!decoded) {
839  warning(0, "Bad cache-directive 0x%02x.", val);
840  goto error;
841  }
842  octstr_append_char(decoded, '=');
843  switch (val) {
844  case WSP_CACHE_CONTROL_NO_CACHE:
845  case WSP_CACHE_CONTROL_PRIVATE:
846  if (parse_octets_left(context) == 0) {
847  warning(0, "Too short cache-directive");
848  goto error;
849  }
850  octstr_append_char(decoded, '"');
851  do {
852  Octstr *fieldname = unpack_field_name(context);
853  if (!fieldname) {
854  warning(0, "Bad field name in cache directive");
855  goto error;
856  }
857  octstr_append(decoded, fieldname);
858  octstr_destroy(fieldname);
859  if (parse_octets_left(context) > 0) {
860  octstr_append_char(decoded, ',');
861  octstr_append_char(decoded, ' ');
862  }
863  } while (parse_octets_left(context) > 0 &&
864  !parse_error(context));
865  octstr_append_char(decoded, '"');
866  break;
867  case WSP_CACHE_CONTROL_MAX_AGE:
868  case WSP_CACHE_CONTROL_MAX_STALE:
869  case WSP_CACHE_CONTROL_MIN_FRESH:
870  {
871  Octstr *seconds;
872  seconds = wsp_unpack_integer_value(context);
873  if (!seconds) {
874  warning(0, "Bad integer value in cache directive");
875  goto error;
876  }
877  octstr_append(decoded, seconds);
878  octstr_destroy(seconds);
879  }
880  break;
881  default:
882  warning(0, "Unexpected value 0x%02x in cache directive.", val);
883  break;
884  }
885  } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
886  /* XXX: WSP grammar seems wrong here. It works out
887  * to Token-text followed by Parameter. But the
888  * grammar in RFC2616 works out to a key = value
889  * pair, i.e. only a Parameter. */
890  decoded = parse_get_nul_string(context);
891  if (!decoded) {
892  warning(0, "Format error in cache-control.");
893  return NULL;
894  }
895  /* Yes, the grammar allows only one */
896  unpack_parameter(context, decoded);
897  } else {
898  panic(0, "Unknown field value type %d.", ret);
899  }
900 
901  return decoded;
902 
903 error:
904  octstr_destroy(decoded);
905  return NULL;
906 }
907 
908 /* Retry-after is defined in 8.4.2.44 */
910 {
911  int selector;
912 
913  selector = parse_get_char(context);
914  if (selector == ABSOLUTE_TIME) {
915  return wsp_unpack_date_value(context);
916  } else if (selector == RELATIVE_TIME) {
917  return wsp_unpack_integer_value(context);
918  } else {
919  warning(0, "Cannot parse retry-after value.");
920  return NULL;
921  }
922 }
923 
924 /* Disposition is defined in 8.4.2.53 */
926 {
927  Octstr *decoded = NULL;
928  int selector;
929 
930  selector = parse_get_char(context) - 128;
931  decoded = wsp_disposition_to_string(selector);
932  if (!decoded) {
933  warning(0, "Cannot parse content-disposition value.");
934  return NULL;
935  }
936  wsp_unpack_all_parameters(context, decoded);
937  return decoded;
938 }
939 
940 /* Range-value is defined in 8.4.2.42 */
942 {
943  Octstr *decoded = NULL;
944  int selector;
945  unsigned long first_byte_pos, last_byte_pos, suffix_length;
946 
947  selector = parse_get_char(context);
948  if (selector == BYTE_RANGE) {
949  first_byte_pos = parse_get_uintvar(context);
950  if (parse_error(context))
951  goto error;
952 
953  decoded = octstr_create("bytes = ");
954  octstr_append_decimal(decoded, first_byte_pos);
955  octstr_append_char(decoded, '-');
956 
957  last_byte_pos = parse_get_uintvar(context);
958  if (parse_error(context)) {
959  /* last_byte_pos is optional */
960  parse_clear_error(context);
961  } else {
962  octstr_append_decimal(decoded, last_byte_pos);
963  }
964  } else if (selector == SUFFIX_BYTE_RANGE) {
965  suffix_length = parse_get_uintvar(context);
966  if (parse_error(context))
967  goto error;
968 
969  decoded = octstr_create("bytes = -");
970  octstr_append_decimal(decoded, suffix_length);
971  } else {
972  goto error;
973  }
974 
975  return decoded;
976 
977 error:
978  warning(0, "Bad format for range-value.");
979  octstr_destroy(decoded);
980  return NULL;
981 }
982 
983 /* Warning-value is defined in 8.4.2.51 */
985 {
986  Octstr *decoded = NULL;
987  Octstr *warn_code = NULL;
988  Octstr *warn_agent = NULL;
989  Octstr *warn_text = NULL;
990  unsigned char quote = '"';
991 
992  warn_code = wsp_unpack_integer_value(context);
993 
994  warn_agent = parse_get_nul_string(context);
995  if (warn_agent && octstr_get_char(warn_agent, 0) == WSP_QUOTE)
996  octstr_delete(warn_agent, 0, 1);
997 
998  warn_text = parse_get_nul_string(context);
999  if (warn_text && octstr_get_char(warn_text, 0) == WSP_QUOTE)
1000  octstr_delete(warn_text, 0, 1);
1001  if (octstr_get_char(warn_text, 0) != quote)
1002  octstr_insert_data(warn_text, 0, (char *)&quote, 1);
1003  if (octstr_get_char(warn_text, octstr_len(warn_text) - 1) != quote)
1004  octstr_append_char(warn_text, quote);
1005 
1006  if (parse_error(context) || !warn_agent || !warn_text)
1007  goto error;
1008 
1009  decoded = octstr_create("");
1010  octstr_append(decoded, warn_code);
1011  octstr_append_char(decoded, ' ');
1012  octstr_append(decoded, warn_agent);
1013  octstr_append_char(decoded, ' ');
1014  octstr_append(decoded, warn_text);
1015 
1016  octstr_destroy(warn_agent);
1017  octstr_destroy(warn_code);
1018  octstr_destroy(warn_text);
1019  return decoded;
1020 
1021 error:
1022  warning(0, "Bad format for warning-value.");
1023  octstr_destroy(warn_agent);
1024  octstr_destroy(warn_code);
1025  octstr_destroy(warn_text);
1026  octstr_destroy(decoded);
1027  return NULL;
1028 }
1029 
1030 void wsp_unpack_well_known_field(List *unpacked, int field_type,
1032 {
1033  int val, ret;
1034  unsigned char *headername = NULL;
1035  unsigned char *ch = NULL;
1036  Octstr *decoded = NULL;
1037 
1038  ret = wsp_field_value(context, &val);
1039  if (parse_error(context)) {
1040  warning(0, "Faulty header, skipping remaining headers.");
1041  parse_skip_to_limit(context);
1042  return;
1043  }
1044 
1045  headername = wsp_header_to_cstr(field_type);
1046  /* headername can still be NULL. This is checked after parsing
1047  * the field value. We want to parse the value before exiting,
1048  * so that we are ready for the next header. */
1049 
1050  /* The following code must set "ch" or "decoded" to a non-NULL
1051  * value if the header is valid. */
1052 
1053  if (ret == WSP_FIELD_VALUE_NUL_STRING) {
1054  /* We allow any header to have a text value, even if that
1055  * is not defined in the grammar. Be generous in what
1056  * you accept, etc. */
1057  /* This covers Text-string, Token-Text, and Uri-value rules */
1058  decoded = parse_get_nul_string(context);
1059  } else if (ret == WSP_FIELD_VALUE_ENCODED) {
1060  switch (field_type) {
1061  case WSP_HEADER_ACCEPT:
1062  case WSP_HEADER_CONTENT_TYPE:
1063  ch = wsp_content_type_to_cstr(val);
1064  if (!ch)
1065  warning(0, "Unknown content type 0x%02x.", val);
1066  break;
1067 
1068  case WSP_HEADER_ACCEPT_CHARSET:
1069  ch = wsp_charset_to_cstr(val);
1070  if (!ch)
1071  warning(0, "Unknown charset 0x%02x.", val);
1072  break;
1073 
1074  case WSP_HEADER_ACCEPT_ENCODING:
1075  case WSP_HEADER_CONTENT_ENCODING:
1076  ch = wsp_encoding_to_cstr(val);
1077  if (!ch)
1078  warning(0, "Unknown encoding 0x%02x.", val);
1079  break;
1080 
1081  case WSP_HEADER_ACCEPT_LANGUAGE:
1082  case WSP_HEADER_CONTENT_LANGUAGE:
1083  ch = wsp_language_to_cstr(val);
1084  if (!ch)
1085  warning(0, "Unknown language 0x%02x.", val);
1086  break;
1087 
1088  case WSP_HEADER_ACCEPT_RANGES:
1089  ch = wsp_ranges_to_cstr(val);
1090  if (!ch)
1091  warning(0, "Unknown ranges value 0x%02x.", val);
1092  break;
1093 
1094  case WSP_HEADER_AGE:
1095  case WSP_HEADER_CONTENT_LENGTH:
1096  case WSP_HEADER_MAX_FORWARDS:
1097  /* Short-integer version of Integer-value */
1098  decoded = octstr_create("");
1099  octstr_append_decimal(decoded, val);
1100  break;
1101 
1102  case WSP_HEADER_ALLOW:
1103  case WSP_HEADER_PUBLIC:
1104  ch = wsp_method_to_cstr(val);
1105  if (!ch) {
1106  /* FIXME Support extended methods */
1107  warning(0, "Unknown method 0x%02x.", val);
1108  }
1109  break;
1110 
1111  case WSP_HEADER_CACHE_CONTROL:
1112  case WSP_HEADER_CACHE_CONTROL_V13:
1113  case WSP_HEADER_CACHE_CONTROL_V14:
1114  ch = wsp_cache_control_to_cstr(val);
1115  if (!ch)
1116  warning(0, "Unknown cache-control value 0x%02x.", val);
1117  break;
1118 
1119  case WSP_HEADER_CONNECTION:
1120  ch = wsp_connection_to_cstr(val);
1121  if (!ch)
1122  warning(0, "Unknown connection value 0x%02x.", val);
1123  break;
1124 
1125 
1126  case WSP_HEADER_PRAGMA:
1127  if (val == 0)
1128  ch = (unsigned char *)"no-cache";
1129  else
1130  warning(0, "Unknown pragma value 0x%02x.", val);
1131  break;
1132 
1133  case WSP_HEADER_TRANSFER_ENCODING:
1134  ch = wsp_transfer_encoding_to_cstr(val);
1135  if (!ch)
1136  warning(0, "Unknown transfer encoding value 0x%02x.", val);
1137  break;
1138 
1139  case WSP_HEADER_VARY:
1140  ch = wsp_header_to_cstr(val);
1141  if (!ch)
1142  warning(0, "Unknown Vary field name 0x%02x.", val);
1143  break;
1144 
1145  case WSP_HEADER_WARNING:
1146  decoded = octstr_create("");
1147  octstr_append_decimal(decoded, val);
1148  break;
1149 
1150  case WSP_HEADER_BEARER_INDICATION:
1151  ch = wsp_bearer_indication_to_cstr(val);
1152  if (!ch)
1153  warning(0, "Unknown Bearer-Indication field name 0x%02x.", val);
1154  break;
1155 
1156  case WSP_HEADER_ACCEPT_APPLICATION:
1157  ch = wsp_application_id_to_cstr(val);
1158  if (!ch)
1159  warning(0, "Unknown Accept-Application field name 0x%02x.", val);
1160  break;
1161 
1162  default:
1163  if (headername) {
1164  warning(0, "Did not expect short-integer with "
1165  "'%s' header, skipping.", headername);
1166  }
1167  break;
1168  }
1169  } else if (ret == WSP_FIELD_VALUE_DATA) {
1170  switch (field_type) {
1171  case WSP_HEADER_ACCEPT:
1172  case WSP_HEADER_CONTENT_TYPE:
1173  /* Content-general-form and Accept-general-form
1174  * are defined separately in WSP, but their
1175  * definitions are equivalent. */
1176  decoded = wsp_unpack_accept_general_form(context);
1177  break;
1178 
1179  case WSP_HEADER_ACCEPT_CHARSET:
1180  decoded = wsp_unpack_accept_charset_general_form(context);
1181  break;
1182 
1183  case WSP_HEADER_ACCEPT_LANGUAGE:
1184  decoded = unpack_accept_language_general_form(context);
1185  break;
1186 
1187  case WSP_HEADER_AGE:
1188  case WSP_HEADER_CONTENT_LENGTH:
1189  case WSP_HEADER_MAX_FORWARDS:
1190  case WSP_HEADER_BEARER_INDICATION:
1191  case WSP_HEADER_ACCEPT_APPLICATION:
1192  /* Long-integer version of Integer-value */
1193  {
1194  long l = unpack_multi_octet_integer(context,
1195  parse_octets_left(context));
1196  decoded = octstr_create("");
1197  octstr_append_decimal(decoded, l);
1198  }
1199  break;
1200 
1201  case WSP_HEADER_AUTHORIZATION:
1202  decoded = unpack_credentials(context);
1203  break;
1204 
1205  case WSP_HEADER_PROXY_AUTHORIZATION:
1206  decoded = proxy_unpack_credentials(context);
1207  break;
1208 
1209  case WSP_HEADER_CACHE_CONTROL:
1210  decoded = unpack_cache_directive(context);
1211  break;
1212 
1213  case WSP_HEADER_CONTENT_MD5:
1214  decoded = parse_get_octets(context,
1215  parse_octets_left(context));
1216  octstr_binary_to_base64(decoded);
1217  /* Zap the CR LF sequence at the end */
1218  octstr_delete(decoded, octstr_len(decoded) - 2, 2);
1219  break;
1220 
1221  case WSP_HEADER_CONTENT_RANGE:
1222  decoded = unpack_content_range(context);
1223  break;
1224 
1225  case WSP_HEADER_DATE:
1226  case WSP_HEADER_EXPIRES:
1227  case WSP_HEADER_IF_MODIFIED_SINCE:
1228  case WSP_HEADER_IF_RANGE:
1229  case WSP_HEADER_IF_UNMODIFIED_SINCE:
1230  case WSP_HEADER_LAST_MODIFIED:
1231  /* Back up to get the length byte again */
1232  parse_skip(context, -1);
1233  decoded = wsp_unpack_date_value(context);
1234  break;
1235 
1236  case WSP_HEADER_PRAGMA:
1237  /* The value is a bare Parameter, without a preceding
1238  * header body. unpack_parameter wasn't really
1239  * designed for this. We work around it here. */
1240  decoded = octstr_create("");
1241  if (unpack_parameter(context, decoded) < 0) {
1242  octstr_destroy(decoded);
1243  decoded = NULL;
1244  } else {
1245  /* Remove the leading "; " */
1246  octstr_delete(decoded, 0, 2);
1247  }
1248  break;
1249 
1250  case WSP_HEADER_PROXY_AUTHENTICATE:
1251  case WSP_HEADER_WWW_AUTHENTICATE:
1252  decoded = unpack_challenge(context);
1253  break;
1254 
1255  case WSP_HEADER_RANGE:
1256  decoded = unpack_range_value(context);
1257  break;
1258 
1259  case WSP_HEADER_RETRY_AFTER:
1260  decoded = unpack_retry_after(context);
1261  break;
1262 
1263  case WSP_HEADER_WARNING:
1264  decoded = unpack_warning_value(context);
1265  break;
1266 
1267  case WSP_HEADER_CONTENT_DISPOSITION:
1268  decoded = unpack_disposition(context);
1269  break;
1270 
1271  case WSP_HEADER_ENCODING_VERSION:
1272  decoded = unpack_encoding_version(context);
1273  break;
1274 
1275  default:
1276  if (headername) {
1277  warning(0, "Did not expect value-length with "
1278  "'%s' header, skipping.", headername);
1279  }
1280  break;
1281  }
1282  if (headername && parse_octets_left(context) > 0) {
1283  warning(0, "WSP: %s: skipping %ld trailing octets.",
1284  headername, parse_octets_left(context));
1285  }
1286  parse_skip_to_limit(context);
1287  parse_pop_limit(context);
1288  } else {
1289  panic(0, "Unknown field-value type %d.", ret);
1290  }
1291 
1292  if (ch == NULL && decoded != NULL)
1293  ch = (unsigned char *)octstr_get_cstr(decoded);
1294  if (ch == NULL)
1295  goto value_error;
1296 
1297  if (!headername) {
1298  warning(0, "Unknown header number 0x%02x.", field_type);
1299  goto value_error;
1300  }
1301 
1302  http_header_add(unpacked, (char *)headername,(char *) ch);
1303  octstr_destroy(decoded);
1304  return;
1305 
1306 value_error:
1307  warning(0, "Skipping faulty header.");
1308  octstr_destroy(decoded);
1309 }
1310 
1312 {
1313  Octstr *header = NULL;
1314  Octstr *value = NULL;
1315 
1316  header = parse_get_nul_string(context);
1317  value = parse_get_nul_string(context);
1318 
1319  if (header && value) {
1320  http_header_add(unpacked, octstr_get_cstr(header),
1321  octstr_get_cstr(value));
1322  }
1323 
1324  if (parse_error(context))
1325  warning(0, "Error parsing application-header.");
1326 
1327  octstr_destroy(header);
1328  octstr_destroy(value);
1329 }
1330 
1331 List *wsp_headers_unpack(Octstr *headers, int content_type_present)
1332 {
1334  int byte;
1335  List *unpacked;
1336  int code_page;
1337 
1338  unpacked = http_create_empty_headers();
1339  context = parse_context_create(headers);
1340 
1341  if (octstr_len(headers) > 0) {
1342  debug("wsp", 0, "WSP: decoding headers:");
1343  octstr_dump(headers, 0);
1344  }
1345 
1346  if (content_type_present)
1347  wsp_unpack_well_known_field(unpacked,
1348  WSP_HEADER_CONTENT_TYPE, context);
1349 
1350  code_page = 1; /* default */
1351 
1352  while (parse_octets_left(context) > 0 && !parse_error(context)) {
1353  byte = parse_get_char(context);
1354 
1355  if (byte == 127 || (byte >= 1 && byte <= 31)) {
1356  if (byte == 127)
1357  code_page = parse_get_char(context);
1358  else
1359  code_page = byte;
1360  if (code_page == 1)
1361  info(0, "Returning to code page 1 (default).");
1362  else {
1363  warning(0, "Shift to unknown code page %d.",
1364  code_page);
1365  warning(0, "Will try to skip headers until "
1366  "next known code page.");
1367  }
1368  } else if (byte >= 128) { /* well-known-header */
1369  if (code_page == 1)
1370  wsp_unpack_well_known_field(unpacked, byte - 128, context);
1371  else {
1372  debug("wsp", 0, "Skipping field 0x%02x.", byte);
1373  wsp_skip_field_value(context);
1374  }
1375  } else if (byte > 31 && byte < 127) {
1376  /* Un-parse the character we just read */
1377  parse_skip(context, -1);
1378  wsp_unpack_app_header(unpacked, context);
1379  } else {
1380  warning(0, "Unsupported token or header (start 0x%x)", byte);
1381  break;
1382  }
1383  }
1384 
1385  if (gwlist_len(unpacked) > 0) {
1386  long i;
1387 
1388  debug("wsp", 0, "WSP: decoded headers:");
1389  for (i = 0; i < gwlist_len(unpacked); i++) {
1390  Octstr *header = gwlist_get(unpacked, i);
1391  debug("wsp", 0, "%s", octstr_get_cstr(header));
1392  }
1393  debug("wsp", 0, "WSP: End of decoded headers.");
1394  }
1395 
1396  parse_context_destroy(context);
1397  return unpacked;
1398 }
1399 
1400 
1401 /**********************************************************************/
1402 /* Start of header packing code (HTTP to WSP) */
1403 /**********************************************************************/
1404 
1405 static int pack_accept(Octstr *packet, Octstr *value);
1406 static int pack_accept_charset(Octstr *packet, Octstr *value);
1407 static int pack_accept_encoding(Octstr *packet, Octstr *value);
1408 static int pack_accept_language(Octstr *packet, Octstr *value);
1409 static int pack_cache_control(Octstr *packet, Octstr *value);
1410 static int pack_challenge(Octstr *packet, Octstr *value);
1411 static int pack_connection(Octstr *packet, Octstr *value);
1412 static int pack_content_disposition(Octstr *packet, Octstr *value);
1413 static int pack_content_range(Octstr *packet, Octstr *value);
1414 static int pack_credentials(Octstr *packet, Octstr *value);
1415 static int pack_encoding(Octstr *packet, Octstr *value);
1416 static int pack_expires(Octstr *packet, Octstr *value);
1417 static int pack_field_name(Octstr *packet, Octstr *value);
1418 static int pack_if_range(Octstr *packet, Octstr *value);
1419 static int pack_language(Octstr *packet, Octstr *value);
1420 static int pack_md5(Octstr *packet, Octstr *value);
1421 static int pack_method(Octstr *packet, Octstr *value);
1422 static int pack_pragma(Octstr *packet, Octstr *value);
1423 static int pack_range(Octstr *packet, Octstr *value);
1424 static int pack_range_unit(Octstr *packet, Octstr *value);
1425 static int pack_transfer_encoding(Octstr *packet, Octstr *value);
1426 static int pack_uri(Octstr *packet, Octstr *value);
1427 static int pack_warning(Octstr *packet, Octstr *value);
1428 
1429 
1430 
1431 /* these are used in MMS encapsulation code too */
1432 
1434  {
1435  { WSP_HEADER_ACCEPT, pack_accept, LIST },
1436  { WSP_HEADER_ACCEPT_CHARSET, pack_accept_charset, LIST },
1437  { WSP_HEADER_ACCEPT_ENCODING, pack_accept_encoding, LIST },
1438  { WSP_HEADER_ACCEPT_LANGUAGE, pack_accept_language, LIST },
1439  { WSP_HEADER_ACCEPT_RANGES, pack_range_unit, LIST },
1440  { WSP_HEADER_AGE, wsp_pack_integer_string, 0 },
1441  /* pack_method is slightly too general because Allow is only
1442  * supposed to encode well-known-methods. */
1443  { WSP_HEADER_ALLOW, pack_method, LIST },
1444  { WSP_HEADER_AUTHORIZATION, pack_credentials, BROKEN_LIST },
1445  { WSP_HEADER_CACHE_CONTROL, pack_cache_control, LIST },
1446  { WSP_HEADER_CACHE_CONTROL_V13, pack_cache_control, LIST },
1447  { WSP_HEADER_CACHE_CONTROL_V14, pack_cache_control, LIST },
1448  { WSP_HEADER_CONNECTION, pack_connection, LIST },
1449  { WSP_HEADER_CONTENT_BASE, pack_uri, 0 },
1450  { WSP_HEADER_CONTENT_ENCODING, pack_encoding, LIST },
1451  { WSP_HEADER_CONTENT_LANGUAGE, pack_language, LIST },
1452  { WSP_HEADER_CONTENT_LENGTH, wsp_pack_integer_string, 0 },
1453  { WSP_HEADER_CONTENT_LOCATION, pack_uri, 0 },
1454  { WSP_HEADER_CONTENT_MD5, pack_md5, 0 },
1455  { WSP_HEADER_CONTENT_RANGE, pack_content_range, 0 },
1456  { WSP_HEADER_CONTENT_TYPE, wsp_pack_content_type, 0 },
1457  { WSP_HEADER_DATE, wsp_pack_date, 0 },
1458  { WSP_HEADER_ETAG, wsp_pack_quoted_text, 0 },
1459  { WSP_HEADER_EXPIRES, pack_expires, 0 },
1460  { WSP_HEADER_FROM, wsp_pack_text, 0 },
1461  { WSP_HEADER_HOST, wsp_pack_text, 0 },
1462  { WSP_HEADER_IF_MODIFIED_SINCE, wsp_pack_date, 0 },
1463  { WSP_HEADER_IF_MATCH, wsp_pack_quoted_text, 0 },
1464  { WSP_HEADER_IF_NONE_MATCH, wsp_pack_quoted_text, 0 },
1465  { WSP_HEADER_IF_RANGE, pack_if_range, 0 },
1466  { WSP_HEADER_IF_UNMODIFIED_SINCE, wsp_pack_date, 0 },
1467  { WSP_HEADER_LAST_MODIFIED, wsp_pack_date, 0 },
1468  { WSP_HEADER_LOCATION, pack_uri, 0 },
1469  { WSP_HEADER_MAX_FORWARDS, wsp_pack_integer_string, 0 },
1470  { WSP_HEADER_PRAGMA, pack_pragma, LIST },
1471  { WSP_HEADER_PROXY_AUTHENTICATE, pack_challenge, BROKEN_LIST },
1472  { WSP_HEADER_PROXY_AUTHORIZATION, pack_credentials, BROKEN_LIST },
1473  { WSP_HEADER_PUBLIC, pack_method, LIST },
1474  { WSP_HEADER_RANGE, pack_range, 0 },
1475  { WSP_HEADER_REFERER, pack_uri, 0 },
1476  { WSP_HEADER_RETRY_AFTER, wsp_pack_retry_after, 0 },
1477  { WSP_HEADER_SERVER, wsp_pack_text, 0 },
1478  { WSP_HEADER_TRANSFER_ENCODING, pack_transfer_encoding, LIST },
1479  { WSP_HEADER_UPGRADE, wsp_pack_text, LIST },
1480  { WSP_HEADER_USER_AGENT, wsp_pack_text, 0 },
1481  { WSP_HEADER_VARY, pack_field_name, LIST },
1482  { WSP_HEADER_VIA, wsp_pack_text, LIST },
1483  { WSP_HEADER_WARNING, pack_warning, LIST },
1484  { WSP_HEADER_WWW_AUTHENTICATE, pack_challenge, BROKEN_LIST },
1485  { WSP_HEADER_CONTENT_DISPOSITION, pack_content_disposition, 0 },
1486  { WSP_HEADER_PUSH_FLAG, wsp_pack_integer_string, 0},
1487  { WSP_HEADER_X_WAP_CONTENT_URI, pack_uri, 0},
1488  { WSP_HEADER_X_WAP_INITIATOR_URI, pack_uri, 0},
1489  { WSP_HEADER_X_WAP_APPLICATION_ID, wsp_pack_integer_string, 0},
1490  { WSP_HEADER_CONTENT_ID, wsp_pack_quoted_text, 0},
1491  { WSP_HEADER_ENCODING_VERSION, wsp_pack_version_value, 0 }
1492  // DAVI { WSP_HEADER_SET_COOKIE, pack_version_value, 0 }
1493  };
1494 
1495 static Parameter *parm_create(Octstr *key, Octstr *value)
1496 {
1497  Parameter *parm;
1498 
1499  parm = gw_malloc(sizeof(*parm));
1500  parm->key = key;
1501  parm->value = value;
1502  return parm;
1503 }
1504 
1506 {
1507  if (parm == NULL)
1508  return;
1509 
1510  octstr_destroy(parm->key);
1511  octstr_destroy(parm->value);
1512  gw_free(parm);
1513 }
1514 
1516 {
1517  parm_destroy(parm);
1518 }
1519 
1520 static Parameter *parm_parse(Octstr *value)
1521 {
1522  long pos;
1523  Octstr *key, *val;
1524 
1525  pos = octstr_search_char(value, '=', 0);
1526  if (pos > 0) {
1527  key = octstr_copy(value, 0, pos);
1528  val = octstr_copy(value, pos + 1, octstr_len(value) - pos);
1529  octstr_strip_blanks(key);
1530  octstr_strip_blanks(val);
1531  } else {
1532  key = octstr_duplicate(value);
1533  val = NULL;
1534  }
1535 
1536  return parm_create(key, val);
1537 }
1538 
1539 /* Many HTTP field elements can take parameters in a standardized
1540  * form: parameters appear after the main value, each is introduced
1541  * by a semicolon (;), and consists of a key=value pair or just
1542  * a key, where the key is a token and the value is either a token
1543  * or a quoted-string.
1544  * The main value itself is a series of tokens, separators, and
1545  * quoted-strings.
1546  *
1547  * This function will take such a field element, and remove all
1548  * parameters from it. The parameters are returned as a List
1549  * of Parameter, where the value field is left NULL
1550  * if the parameter was just a key.
1551  * It returns NULL if there were no parameters.
1552  */
1554 {
1555  long pos;
1556  long len;
1557  int c;
1558  long end;
1559  List *parms;
1560  long firstparm;
1561 
1562  len = octstr_len(value);
1563  /* Find the start of the first parameter. */
1564  for (pos = 0; pos < len; pos++) {
1565  c = octstr_get_char(value, pos);
1566  if (c == ';')
1567  break;
1568  else if (c == '"')
1569  pos += http_header_quoted_string_len(value, pos) - 1;
1570  }
1571 
1572  if (pos >= len)
1573  return NULL; /* no parameters */
1574 
1575  parms = gwlist_create();
1576  firstparm = pos;
1577 
1578  for (pos++; pos > 0 && pos < len; pos++) {
1579  Octstr *key = NULL;
1580  Octstr *val = NULL;
1581 
1582  end = octstr_search_char(value, '=', pos);
1583  if (end < 0)
1584  end = octstr_search_char(value, ';', pos);
1585  if (end < 0)
1586  end = octstr_len(value);
1587  key = octstr_copy(value, pos, end - pos);
1588  octstr_strip_blanks(key);
1589  pos = end;
1590 
1591  if (octstr_get_char(value, pos) == '=') {
1592  pos++;
1593  while (isspace(octstr_get_char(value, pos)))
1594  pos++;
1595  if (octstr_get_char(value, pos) == '"')
1596  end = pos + http_header_quoted_string_len(value, pos);
1597  else
1598  end = octstr_search_char(value, ';', pos);
1599  if (end < 0)
1600  end = octstr_len(value);
1601  val = octstr_copy(value, pos, end - pos);
1602  octstr_strip_blanks(val);
1603  pos = end;
1604  pos = octstr_search_char(value, ';', pos);
1605  }
1606 
1607  gwlist_append(parms, parm_create(key, val));
1608  }
1609 
1610  octstr_delete(value, firstparm, octstr_len(value) - firstparm);
1611  octstr_strip_blanks(value);
1612  return parms;
1613 }
1614 
1616 {
1617  /* This check catches 0-length strings as well, because
1618  * octstr_get_char will return -1. */
1619  if (octstr_get_char(text, 0) >= 128 || octstr_get_char(text, 0) < 32)
1620  octstr_append_char(packed, WSP_QUOTE);
1621  octstr_append(packed, text);
1622  octstr_append_char(packed, 0);
1623  return 0;
1624 }
1625 
1626 /* Pack a string as quoted-text WAP WSP 203, Section 8.4.2.1 */
1628 {
1629  octstr_append_char(packed, '"');
1630  octstr_append(packed,text);
1631  octstr_append_char(packed,0);
1632  return 0;
1633 }
1634 
1635 /* Pack text as Quoted-string if it starts with a " character.
1636  * Pack it as Text-string otherwise. */
1637 static void pack_quoted_string(Octstr *packed, Octstr *text)
1638 {
1639  octstr_append(packed, text);
1640  if (octstr_get_char(text, octstr_len(text) - 1) == '"' &&
1641  octstr_get_char(text, 0) == '"')
1642  octstr_delete(packed, octstr_len(packed) - 1, 1);
1643  octstr_append_char(packed, 0);
1644 }
1645 
1646 /* Is this char in the 'separators' set defined by HTTP? */
1647 static int is_separator_char(int c)
1648 {
1649  switch (c) {
1650  case '(':
1651  case ')':
1652  case '<':
1653  case '>':
1654  case '@':
1655  case ',':
1656  case ';':
1657  case ':':
1658  case '\\':
1659  case '"':
1660  case '/':
1661  case '[':
1662  case ']':
1663  case '?':
1664  case '=':
1665  case '{':
1666  case '}':
1667  case 32: /* SP */
1668  case 9: /* HT */
1669  return 1;
1670  default:
1671  return 0;
1672  }
1673 }
1674 
1675 /* Is this char part of a 'token' as defined by HTTP? */
1676 static int is_token_char(int c)
1677 {
1678  return c >= 32 && c < 127 && !is_separator_char(c);
1679 }
1680 
1681 /* Is this string a 'token' as defined by HTTP? */
1682 static int is_token(Octstr *token)
1683 {
1684  return octstr_len(token) > 0 &&
1685  octstr_check_range(token, 0, octstr_len(token), is_token_char);
1686 }
1687 
1688 /* We represent qvalues as integers from 0 through 1000, rather than
1689  * as floating values. */
1690 static int parse_qvalue(Octstr *value)
1691 {
1692  int qvalue;
1693 
1694  if (value == NULL)
1695  return -1;
1696 
1697  if (!isdigit(octstr_get_char(value, 0)))
1698  return -1;
1699 
1700  qvalue = (octstr_get_char(value, 0) - '0') * 1000;
1701 
1702  if (octstr_get_char(value, 1) != '.')
1703  goto gotvalue;
1704 
1705  if (!isdigit(octstr_get_char(value, 2)))
1706  goto gotvalue;
1707  qvalue += (octstr_get_char(value, 2) - '0') * 100;
1708 
1709 
1710  if (!isdigit(octstr_get_char(value, 3)))
1711  goto gotvalue;
1712  qvalue += (octstr_get_char(value, 3) - '0') * 10;
1713 
1714  if (!isdigit(octstr_get_char(value, 4)))
1715  goto gotvalue;
1716  qvalue += (octstr_get_char(value, 4) - '0');
1717 
1718 gotvalue:
1719  if (qvalue < 0 || qvalue > 1000)
1720  return -1;
1721 
1722  return qvalue;
1723 }
1724 
1725 static int get_qvalue(List *parms, int default_qvalue)
1726 {
1727  long i;
1728  Parameter *parm;
1729  int qvalue;
1730 
1731  for (i = 0; i < gwlist_len(parms); i++) {
1732  parm = gwlist_get(parms, i);
1733  if (octstr_str_compare(parm->key, "q") == 0 ||
1734  octstr_str_compare(parm->key, "Q") == 0) {
1735  qvalue = parse_qvalue(parm->value);
1736  if (qvalue >= 0)
1737  return qvalue;
1738  }
1739  }
1740 
1741  return default_qvalue;
1742 }
1743 
1744 static int pack_qvalue(Octstr *packed, int qvalue)
1745 {
1746  /* "Quality factor 1 is the default value and shall never
1747  * be sent." */
1748  if (qvalue == 1000)
1749  return -1;
1750 
1751  /* Remember that our qvalues are already multiplied by 1000. */
1752  if (qvalue % 10 == 0)
1753  qvalue = qvalue / 10 + 1;
1754  else
1755  qvalue = qvalue + 100;
1756  octstr_append_uintvar(packed, qvalue);
1757  return 0;
1758 }
1759 
1760 /* Pack value as a Value-length followed by the encoded value. */
1761 void wsp_pack_value(Octstr *packed, Octstr *encoded)
1762 {
1763  long len;
1764 
1765  len = octstr_len(encoded);
1766  if (len <= 30)
1767  octstr_append_char(packed, len);
1768  else {
1769  octstr_append_char(packed, 31);
1770  octstr_append_uintvar(packed, len);
1771  }
1772 
1773  octstr_append(packed, encoded);
1774 }
1775 
1776 void wsp_pack_long_integer(Octstr *packed, unsigned long integer)
1777 {
1778  long oldlen = octstr_len(packed);
1779  unsigned char octet;
1780  long len;
1781 
1782  if (integer == 0) {
1783  /* The Multi-octet-integer has to be at least 1 octet long. */
1784  octstr_append_char(packed, 1); /* length */
1785  octstr_append_char(packed, 0); /* value */
1786  return;
1787  }
1788 
1789  /* Encode it back-to-front, by repeatedly inserting
1790  * at the same position, because that's easier. */
1791  for (len = 0; integer != 0; integer >>= 8, len++) {
1792  octet = integer & 0xff;
1793  octstr_insert_data(packed, oldlen, (char *)&octet, 1);
1794  }
1795 
1796  octet = len;
1797  octstr_insert_data(packed, oldlen, (char *)&octet, 1);
1798 }
1799 
1800 void wsp_pack_short_integer(Octstr *packed, unsigned long integer)
1801 {
1802  gw_assert(integer <= MAX_SHORT_INTEGER);
1803 
1804  octstr_append_char(packed, integer + 0x80);
1805 }
1806 
1807 void wsp_pack_integer_value(Octstr *packed, unsigned long integer)
1808 {
1809  if (integer <= MAX_SHORT_INTEGER)
1810  wsp_pack_short_integer(packed, integer);
1811  else
1812  wsp_pack_long_integer(packed, integer);
1813 }
1814 
1816 {
1817  unsigned long integer;
1818  long pos;
1819  int c;
1820  int digit;
1821 
1822  integer = 0;
1823  for (pos = 0; pos < octstr_len(value); pos++) {
1824  c = octstr_get_char(value, pos);
1825  if (!isdigit(c))
1826  break;
1827  digit = c - '0';
1828  if (integer > ULONG_MAX / 10)
1829  goto overflow;
1830  integer *= 10;
1831  if (integer > ULONG_MAX - digit)
1832  goto overflow;
1833  integer += digit;
1834  }
1835 
1836  debug("wsp",0,"WSP: %s: value `%s', integer 0x%04lx", __func__,
1837  octstr_get_cstr(value), integer);
1838  wsp_pack_integer_value(packed, integer);
1839  return 0;
1840 
1841 overflow:
1842  warning(0, "WSP: Number too large to handle: '%s'.",
1843  octstr_get_cstr(value));
1844  return -1;
1845 }
1846 
1847 
1848 int wsp_pack_version_value(Octstr *packed, Octstr *version)
1849 {
1850  unsigned long integer;
1851  long major, minor;
1852  long pos;
1853 
1854  pos = octstr_parse_long(&major, version, 0, 10);
1855  if (pos < 0 || major < 1 || major > 7)
1856  goto usetext;
1857 
1858  if (pos == octstr_len(version))
1859  minor = 15;
1860  else {
1861  if (octstr_get_char(version, pos) != '.')
1862  goto usetext;
1863  pos = octstr_parse_long(&minor, version, pos + 1, 10);
1864  if (pos != octstr_len(version) || minor < 0 || minor > 14)
1865  goto usetext;
1866  }
1867 
1868  integer = major << 4 | minor;
1869  debug("wsp",0,"WSP: %s: value `%s', integer 0x%04lx", __func__,
1870  octstr_get_cstr(version), integer);
1871  wsp_pack_short_integer(packed, integer);
1872  return 0;
1873 
1874 usetext:
1875  wsp_pack_text(packed, version);
1876  return 0;
1877 }
1878 
1879 int wsp_pack_constrained_value(Octstr *packed, Octstr *text, long value)
1880 {
1881  if (value >= 0)
1882  wsp_pack_short_integer(packed, value);
1883  else
1884  wsp_pack_text(packed, text);
1885  return 0;
1886 }
1887 
1888 static void pack_parameter(Octstr *packed, Parameter *parm)
1889 {
1890  long keytoken;
1891  long tmp;
1892  long start;
1893 
1894  start = octstr_len(packed);
1895 
1896  /* Parameter = Typed-parameter | Untyped-parameter */
1897  /* keytoken = wsp_string_to_parameter(parm->key); */
1898  /* XXX this should obey what kind of WSP Encoding-Version the client is using */
1899  keytoken = wsp_string_to_versioned_parameter(parm->key, WSP_1_2);
1900 
1901  if (keytoken >= 0) {
1902  /* Typed-parameter = Well-known-parameter-token Typed-value */
1903  /* Well-known-parameter-token = Integer-value */
1904  wsp_pack_integer_value(packed, keytoken);
1905  /* Typed-value = Compact-value | Text-value */
1906  /* First try to pack as Compact-value or No-value.
1907  * If that fails, pack as Text-value. */
1908  if (parm->value == NULL) {
1909  octstr_append_char(packed, 0); /* No-value */
1910  return;
1911  } else switch (keytoken) {
1912  case 0: /* q */
1913  tmp = parse_qvalue(parm->value);
1914  if (tmp >= 0) {
1915  if (pack_qvalue(packed, tmp) < 0)
1916  octstr_delete(packed, start,
1917  octstr_len(packed) - start);
1918  return;
1919  }
1920  break;
1921  case 1: /* charset */
1922  tmp = wsp_string_to_charset(parm->value);
1923  if (tmp >= 0) {
1924  wsp_pack_integer_value(packed, tmp);
1925  return;
1926  }
1927  break;
1928  case 2: /* level */
1929  wsp_pack_version_value(packed, parm->value);
1930  return;
1931  case 3: /* type */
1932  if (octstr_check_range(parm->value, 0,
1933  octstr_len(parm->value),
1934  gw_isdigit) &&
1935  wsp_pack_integer_string(packed, parm->value) >= 0)
1936  return;
1937  break;
1938  case 5: /* name */
1939  case 6: /* filename */
1940  break;
1941  case 7: /* differences */
1942  if (pack_field_name(packed, parm->value) >= 0)
1943  return;
1944  break;
1945  case 8: /* padding */
1946  if (octstr_parse_long(&tmp, parm->value, 0, 10)
1947  == octstr_len(parm->value) &&
1948  tmp >= 0 && tmp <= MAX_SHORT_INTEGER) {
1949  wsp_pack_short_integer(packed, tmp);
1950  return;
1951  }
1952  break;
1953  }
1954  pack_quoted_string(packed, parm->value);
1955  } else {
1956  /* Untyped-parameter = Token-text Untyped-value */
1957  wsp_pack_text(packed, parm->key);
1958  /* Untyped-value = Integer-value | Text-value */
1959  if (parm->value == NULL) {
1960  octstr_append_char(packed, 0); /* No-value */
1961  return;
1962  }
1963  /* If we can pack as integer, do so. */
1964  if (octstr_parse_long(&tmp, parm->value, 0, 10)
1965  == octstr_len(parm->value)) {
1966  wsp_pack_integer_value(packed, tmp);
1967  } else {
1968  pack_quoted_string(packed, parm->value);
1969  }
1970  }
1971 }
1972 
1973 void wsp_pack_parameters(Octstr *packed, List *parms)
1974 {
1975  long i;
1976  Parameter *parm;
1977 
1978  for (i = 0; i < gwlist_len(parms); i++) {
1979  parm = gwlist_get(parms, i);
1980  pack_parameter(packed, parm);
1981  }
1982 }
1983 
1984 static int pack_uri(Octstr *packed, Octstr *value)
1985 {
1986  wsp_pack_text(packed, value);
1987  return 0;
1988 }
1989 
1990 static int pack_md5(Octstr *packed, Octstr *value)
1991 {
1992  Octstr *binary;
1993 
1994  binary = octstr_duplicate(value);
1995  octstr_base64_to_binary(binary);
1996 
1997  if (octstr_len(binary) != 16) {
1998  error(0, "WSP: MD5 value not 128 bits.");
1999  return -1;
2000  }
2001 
2002  octstr_append_char(packed, 16);
2003  octstr_append(packed, binary);
2004 
2005  octstr_destroy(binary);
2006 
2007  return 0;
2008 }
2009 
2010 /* Actually packs a "Value-length Challenge" */
2011 /* Relies on http_split_auth_value to have converted the entry to
2012  * the normal HTTP parameter format rather than the comma-separated
2013  * one used by challenge and credentials. */
2014 static int pack_challenge(Octstr *packed, Octstr *value)
2015 {
2016  Octstr *encoding = NULL;
2017  Octstr *scheme = NULL;
2018  Octstr *basic = octstr_imm("Basic");
2019  Octstr *realm = octstr_imm("realm");
2020  Octstr *parmstring = NULL;
2021  List *parms = NULL;
2022  Parameter *realmparm = NULL;
2023  long realmpos = -1;
2024  Octstr *realmval = NULL;
2025  long pos;
2026 
2027  encoding = octstr_create("");
2028 
2029  /* Get authentication scheme */
2030  for (pos = 0; pos < octstr_len(value); pos++) {
2031  if (!is_token_char(octstr_get_char(value, pos)))
2032  break;
2033  }
2034  scheme = octstr_copy(value, 0, pos);
2035  octstr_strip_blanks(scheme);
2036 
2037  /* Skip whitespace */
2038  while (isspace(octstr_get_char(value, pos)))
2039  pos++;
2040 
2041  if (octstr_case_compare(scheme, basic) == 0) {
2042  parmstring = octstr_copy(value, pos, octstr_len(value) - pos);
2043  realmparm = parm_parse(parmstring);
2044 
2046  realmpos = octstr_len(encoding);
2047  } else {
2048  long i;
2049 
2050  wsp_pack_text(encoding, scheme);
2051  realmpos = octstr_len(encoding);
2052 
2053  /* Find the realm parameter and exclude it */
2054  parms = wsp_strip_parameters(value);
2055  for (i = 0; i < gwlist_len(parms); i++) {
2056  Parameter *parm = gwlist_get(parms, i);
2057  if (octstr_case_compare(realm, parm->key) == 0) {
2058  realmparm = parm;
2059  gwlist_delete(parms, i, 1);
2060  break;
2061  }
2062  }
2063 
2064  wsp_pack_parameters(encoding, parms);
2065  }
2066 
2067  /*
2068  * In the WSP encoding we have to put the realm value first, but
2069  * with non-Basic challenges we don't know if it will come first
2070  * in the HTTP header. So we just start parsing parameters, and
2071  * go back and insert the realm value later. The same technique
2072  * is used for Basic authentication to simplify the code.
2073  */
2074 
2075  if (realmparm == NULL ||
2076  octstr_case_compare(realmparm->key, realm) != 0 ||
2077  realmparm->value == NULL)
2078  goto error;
2079 
2080  /* Zap quote marks */
2081  if (octstr_get_char(realmparm->value, 0) == '"' &&
2082  octstr_get_char(realmparm->value, octstr_len(realmparm->value) - 1) == '"') {
2083  octstr_delete(realmparm->value, 0, 1);
2084  octstr_delete(realmparm->value, octstr_len(realmparm->value) - 1, 1);
2085  }
2086 
2087  gw_assert(realmpos >= 0);
2088 
2089  realmval = octstr_create("");
2090  wsp_pack_text(realmval, realmparm->value);
2091  octstr_insert(encoding, realmval, realmpos);
2092 
2093  wsp_pack_value(packed, encoding);
2094 
2095  octstr_destroy(encoding);
2096  octstr_destroy(scheme);
2097  octstr_destroy(parmstring);
2098  parm_destroy(realmparm);
2100  octstr_destroy(realmval);
2101  return 0;
2102 
2103 error:
2104  warning(0, "WSP: Cannot parse challenge.");
2105  octstr_destroy(encoding);
2106  octstr_destroy(scheme);
2107  octstr_destroy(parmstring);
2108  parm_destroy(realmparm);
2110  octstr_destroy(realmval);
2111  return -1;
2112 }
2113 
2114 /* Actually packs a "Value-length Credentials" */
2115 /* Relies on http_split_auth_value to have converted the entry to
2116  * the normal HTTP parameter format rather than the comma-separated
2117  * one used by challenge and credentials. */
2118 static int pack_credentials(Octstr *packed, Octstr *value)
2119 {
2120  Octstr *encoding = NULL;
2121  Octstr *scheme = NULL;
2122  Octstr *basic = NULL;
2123  long pos;
2124 
2125  encoding = octstr_create("");
2126 
2127  /* Get authentication scheme */
2128  for (pos = 0; pos < octstr_len(value); pos++) {
2129  if (!is_token_char(octstr_get_char(value, pos)))
2130  break;
2131  }
2132  scheme = octstr_copy(value, 0, pos);
2133  octstr_strip_blanks(scheme);
2134 
2135  /* Skip whitespace */
2136  while (isspace(octstr_get_char(value, pos)))
2137  pos++;
2138 
2139  basic = octstr_imm("Basic");
2140  if (octstr_case_compare(scheme, basic) == 0) {
2141  Octstr *cookie;
2142  Octstr *userid;
2143  Octstr *password;
2144 
2146 
2147  cookie = octstr_copy(value, pos, octstr_len(value) - pos);
2148  octstr_base64_to_binary(cookie);
2149  pos = octstr_search_char(cookie, ':', 0);
2150  if (pos < 0) {
2151  warning(0, "WSP: bad cookie in credentials '%s'.",
2152  octstr_get_cstr(value));
2153  octstr_destroy(cookie);
2154  goto error;
2155  }
2156 
2157  userid = octstr_copy(cookie, 0, pos);
2158  password = octstr_copy(cookie, pos + 1, octstr_len(cookie) - pos);
2159  wsp_pack_text(encoding, userid);
2160  wsp_pack_text(encoding, password);
2161 
2162  octstr_destroy(cookie);
2163  octstr_destroy(userid);
2164  octstr_destroy(password);
2165  } else {
2166  List *parms;
2167 
2168  wsp_pack_text(encoding, scheme);
2169  parms = wsp_strip_parameters(value);
2170  wsp_pack_parameters(encoding, parms);
2172  }
2173 
2174  wsp_pack_value(packed, encoding);
2175  octstr_destroy(encoding);
2176  octstr_destroy(scheme);
2177 
2178  return 0;
2179 
2180 error:
2181  octstr_destroy(encoding);
2182  octstr_destroy(scheme);
2183  return -1;
2184 }
2185 
2186 int wsp_pack_date(Octstr *packed, Octstr *value)
2187 {
2188  long timeval;
2189 
2190  /* If we get a negative timeval here, this means either
2191  * we're beyond the time_t 32 bit int positive border for the
2192  * timestamp or we're really handling time before epoch. */
2193  timeval = date_parse_http(value);
2194  if (timeval == -1) {
2195  warning(0, "WSP headers: cannot decode date '%s'",
2196  octstr_get_cstr(value));
2197  return -1;
2198  }
2199 
2200  /* We'll assume that we don't package time before epoch. */
2201  wsp_pack_long_integer(packed, (unsigned long) timeval);
2202  return 0;
2203 }
2204 
2205 static int pack_connection(Octstr *packed, Octstr *value)
2206 {
2207  return wsp_pack_constrained_value(packed, value,
2208  wsp_string_to_connection(value));
2209 }
2210 
2211 static int pack_encoding(Octstr *packed, Octstr *value)
2212 {
2213  return wsp_pack_constrained_value(packed, value,
2214  wsp_string_to_encoding(value));
2215 }
2216 
2217 static int pack_field_name(Octstr *packed, Octstr *value)
2218 {
2219  /* XXX we need to obey which WSP encoding-version to use */
2220  /* return pack_constrained_value(packed, value,
2221  wsp_string_to_header(value)); */
2222  return wsp_pack_constrained_value(packed, value,
2223  wsp_string_to_versioned_header(value, WSP_1_2));
2224 }
2225 
2226 static int pack_language(Octstr *packed, Octstr *value)
2227 {
2228  long language;
2229 
2230  /* Can't use pack_constrained_value here because
2231  * language does not necessarily fit in a Short-integer. */
2232  language = wsp_string_to_language(value);
2233  if (language >= 0)
2234  wsp_pack_integer_value(packed, language);
2235  else
2236  wsp_pack_text(packed, value);
2237  return 0;
2238 }
2239 
2240 /* Encode value as Well-known-method | Token-text */
2241 static int pack_method(Octstr *packed, Octstr *value)
2242 {
2243  /* In the future, we will need some way to refer to extended
2244  * method names negotiated for this session. */
2245  return wsp_pack_constrained_value(packed, value,
2246  wsp_string_to_method(value));
2247 }
2248 
2249 /* Encode value as Accept-ranges-value */
2250 static int pack_range_unit(Octstr *packed, Octstr *value)
2251 {
2252  return wsp_pack_constrained_value(packed, value,
2253  wsp_string_to_ranges(value));
2254 }
2255 
2256 /* Encode byte-range-spec | suffix-byte-range-spec as Range-value.
2257  * Return position after the parsed spec. */
2258 static int pack_range_value(Octstr *packed, Octstr *value, long pos)
2259 {
2260  long first_byte_pos;
2261  long last_byte_pos;
2262  long suffix_length;
2263  Octstr *encoding;
2264 
2265  while (isspace(octstr_get_char(value, pos)))
2266  pos++;
2267 
2268  if (isdigit(octstr_get_char(value, pos))) {
2269  /* byte-range-spec */
2270  pos = octstr_parse_long(&first_byte_pos, value, pos, 10);
2271  if (pos < 0 || first_byte_pos < 0)
2272  return -1;
2273 
2274  while (isspace(octstr_get_char(value, pos)))
2275  pos++;
2276 
2277  if (octstr_get_char(value, pos) != '-')
2278  return -1;
2279  pos++;
2280 
2281  while (isspace(octstr_get_char(value, pos)))
2282  pos++;
2283 
2284  if (isdigit(octstr_get_char(value, pos))) {
2285  pos = octstr_parse_long(&last_byte_pos, value, pos, 10);
2286  if (pos < 0 || last_byte_pos < 0)
2287  return -1;
2288  } else {
2289  last_byte_pos = -1;
2290  }
2291 
2292  encoding = octstr_create("");
2293  octstr_append_char(encoding, BYTE_RANGE);
2294  octstr_append_uintvar(encoding, first_byte_pos);
2295  if (last_byte_pos >= 0)
2296  octstr_append_uintvar(encoding, last_byte_pos);
2297  wsp_pack_value(packed, encoding);
2298  octstr_destroy(encoding);
2299  } else if (octstr_get_char(value, pos) == '-') {
2300  /* suffix-byte-range-spec */
2301  pos++;
2302 
2303  pos = octstr_parse_long(&suffix_length, value, pos, 10);
2304  if (pos < 0 || suffix_length < 0)
2305  return -1;
2306 
2307  encoding = octstr_create("");
2309  octstr_append_uintvar(encoding, suffix_length);
2310  wsp_pack_value(packed, encoding);
2311  octstr_destroy(encoding);
2312  } else
2313  return -1;
2314 
2315  return pos;
2316 }
2317 
2318 static int pack_transfer_encoding(Octstr *packed, Octstr *value)
2319 {
2320  return wsp_pack_constrained_value(packed, value,
2321  wsp_string_to_transfer_encoding(value));
2322 }
2323 
2324 /* Also used by pack_content_type */
2325 static int pack_accept(Octstr *packed, Octstr *value)
2326 {
2327  List *parms;
2328  long media;
2329 
2330  parms = wsp_strip_parameters(value);
2331  /* XXX we need to obey which WSP encoding-version to use */
2332  /* media = wsp_string_to_content_type(value); */
2333  media = wsp_string_to_versioned_content_type(value, WSP_1_2);
2334 
2335  /* See if we can fit this in a Constrained-media encoding */
2336  if (parms == NULL && media <= MAX_SHORT_INTEGER) {
2337  wsp_pack_constrained_value(packed, value, media);
2338  } else {
2339  Octstr *encoding = octstr_create("");
2340 
2341  if (media >= 0)
2342  wsp_pack_integer_value(encoding, media);
2343  else
2344  wsp_pack_text(encoding, value);
2345 
2346  wsp_pack_parameters(encoding, parms);
2347  wsp_pack_value(packed, encoding);
2348  octstr_destroy(encoding);
2349  }
2350 
2352  return 0;
2353 }
2354 
2355 static int pack_accept_charset(Octstr *packed, Octstr *value)
2356 {
2357  List *parms;
2358  long charset;
2359  long qvalue;
2360 
2361  parms = wsp_strip_parameters(value);
2362  charset = wsp_string_to_charset(value);
2363  qvalue = 1000;
2364  if (parms)
2365  qvalue = get_qvalue(parms, qvalue);
2367 
2368  /* See if we can fit this in a Constrained-charset encoding */
2369  if (qvalue == 1000 && charset <= MAX_SHORT_INTEGER) {
2370  wsp_pack_constrained_value(packed, value, charset);
2371  } else {
2372  Octstr *encoding = octstr_create("");
2373 
2374  if (charset >= 0)
2375  wsp_pack_integer_value(encoding, charset);
2376  else
2377  wsp_pack_text(encoding, value);
2378 
2379  if (qvalue != 1000)
2380  pack_qvalue(encoding, qvalue);
2381  wsp_pack_value(packed, encoding);
2382  octstr_destroy(encoding);
2383  }
2384 
2385  return 0;
2386 }
2387 
2388 /* WSP 8.4.2.9 does not specify any way to encode parameters for
2389  * an Accept-encoding field, but RFC2616 allows q parameters.
2390  * We'll have to simplify: qvalue > 0 means encode it, qvalue == 0
2391  * means don't encode it.
2392  */
2393 static int pack_accept_encoding(Octstr *packed, Octstr *value)
2394 {
2395  List *parms;
2396  int qvalue;
2397 
2398  qvalue = 1000; /* default */
2399 
2400  parms = wsp_strip_parameters(value);
2401  if (parms)
2402  qvalue = get_qvalue(parms, qvalue);
2404 
2405  if (qvalue > 0) {
2406  if (qvalue < 1000)
2407  warning(0, "Cannot encode q-value in Accept-Encoding.");
2408  pack_encoding(packed, value);
2409  } else {
2410  warning(0, "Cannot encode q=0 in Accept-Encoding; skipping this encoding.");
2411  return -1;
2412  }
2413 
2414  return 0;
2415 }
2416 
2417 static int pack_accept_language(Octstr *packed, Octstr *value)
2418 {
2419  List *parms;
2420  long language;
2421  long qvalue;
2422 
2423  parms = wsp_strip_parameters(value);
2424  language = wsp_string_to_language(value);
2425  qvalue = 1000;
2426  if (parms)
2427  qvalue = get_qvalue(parms, qvalue);
2429 
2430  /* See if we can fit this in a Constrained-language encoding. */
2431  /* Note that our language table already includes Any-language */
2432  if (qvalue == 1000 && language <= MAX_SHORT_INTEGER) {
2433  wsp_pack_constrained_value(packed, value, language);
2434  } else {
2435  Octstr *encoding = octstr_create("");
2436 
2437  if (language >= 0)
2438  wsp_pack_integer_value(encoding, language);
2439  else
2440  wsp_pack_text(encoding, value);
2441 
2442  if (qvalue != 1000)
2443  pack_qvalue(encoding, qvalue);
2444  wsp_pack_value(packed, encoding);
2445  octstr_destroy(encoding);
2446  }
2447 
2448  return 0;
2449 }
2450 
2451 static int pack_cache_control(Octstr *packed, Octstr *value)
2452 {
2453  Parameter *parm;
2454  long tmp;
2455 
2456  parm = parm_parse(value);
2457 
2458  if (parm->value == NULL) {
2459  wsp_pack_constrained_value(packed, value,
2460  wsp_string_to_cache_control(parm->key));
2461  } else {
2462  Octstr *encoding = octstr_create("");
2463 
2464  tmp = wsp_string_to_cache_control(parm->key);
2465  if (tmp < 0) {
2466  /* According to WSP 8.4.2.15, the format
2467  * is "Cache-extension Parameter", and
2468  * Cache-extension is a Token-text.
2469  * But in HTTP a cache-extension is of
2470  * the form token=value, which maps
2471  * nicely to Parameter. So what is
2472  * this extra Token-text? I decided to leave it blank.
2473  * - Richard Braakman
2474  */
2475  wsp_pack_text(encoding, octstr_imm(""));
2476  pack_parameter(encoding, parm);
2477  } else {
2478  int done = 0;
2479  Octstr *value_encoding;
2480  List *names;
2481  Octstr *element;
2482 
2483  value_encoding = octstr_create("");
2484  switch (tmp) {
2485  case WSP_CACHE_CONTROL_NO_CACHE:
2486  case WSP_CACHE_CONTROL_PRIVATE:
2487  if (octstr_get_char(parm->value, 0) == '"')
2488  octstr_delete(parm->value, 0, 1);
2489  if (octstr_get_char(parm->value, octstr_len(parm->value) - 1) == '"')
2490  octstr_delete(parm->value, octstr_len(parm->value) - 1, 1);
2491  names = http_header_split_value(parm->value);
2492  while ((element = gwlist_consume(names))) {
2493  pack_field_name(value_encoding, element);
2494  octstr_destroy(element);
2495  }
2497  done = 1;
2498  break;
2499 
2500  case WSP_CACHE_CONTROL_MAX_AGE:
2501  case WSP_CACHE_CONTROL_MAX_STALE:
2502  case WSP_CACHE_CONTROL_MIN_FRESH:
2503  if (wsp_pack_integer_string(value_encoding, parm->value) >= 0)
2504  done = 1;
2505  break;
2506  }
2507 
2508  if (done) {
2509  wsp_pack_short_integer(encoding, tmp);
2510  octstr_append(encoding, value_encoding);
2511  } else {
2512  /* See note above */
2513  pack_parameter(encoding, parm);
2514  }
2515  octstr_destroy(value_encoding);
2516  }
2517 
2518  wsp_pack_value(packed, encoding);
2519  octstr_destroy(encoding);
2520  }
2521 
2522  parm_destroy(parm);
2523  return 1;
2524 }
2525 
2526 static int pack_content_disposition(Octstr *packed, Octstr *value)
2527 {
2528  List *parms;
2529  long disposition;
2530 
2531  parms = wsp_strip_parameters(value);
2532  disposition = wsp_string_to_disposition(value);
2533 
2534  if (disposition >= 0) {
2535  Octstr *encoding = octstr_create("");
2536 
2537  wsp_pack_short_integer(encoding, disposition);
2538  wsp_pack_parameters(encoding, parms);
2539  wsp_pack_value(packed, encoding);
2540  octstr_destroy(encoding);
2541  } else {
2542  warning(0, "WSP: Cannot encode Content-Disposition '%s'.",
2543  octstr_get_cstr(value));
2544  goto error;
2545  }
2546 
2548  return 0;
2549 
2550 error:
2552  return -1;
2553 }
2554 
2555 static int pack_content_range(Octstr *packed, Octstr *value)
2556 {
2557  Octstr *bytes;
2558  long pos;
2559  long firstbyte, lastbyte, instancelen;
2560  Octstr *encoding;
2561 
2562  bytes = octstr_imm("bytes ");
2563  if (octstr_ncompare(value, bytes, octstr_len(bytes)) != 0)
2564  goto error;
2565 
2566  pos = octstr_len(bytes);
2567  while (isspace(octstr_get_char(value, pos)))
2568  pos++;
2569  if (octstr_get_char(value, pos) == '*')
2570  goto warning;
2571  pos = octstr_parse_long(&firstbyte, value, pos, 10);
2572  if (pos < 0)
2573  goto error;
2574 
2575  while (isspace(octstr_get_char(value, pos)))
2576  pos++;
2577  if (octstr_get_char(value, pos++) != '-')
2578  goto error;
2579 
2580  pos = octstr_parse_long(&lastbyte, value, pos, 10);
2581  if (pos < 0)
2582  goto error;
2583 
2584  while (isspace(octstr_get_char(value, pos)))
2585  pos++;
2586  if (octstr_get_char(value, pos++) != '/')
2587  goto error;
2588 
2589  while (isspace(octstr_get_char(value, pos)))
2590  pos++;
2591  if (octstr_get_char(value, pos) == '*')
2592  goto warning;
2593  pos = octstr_parse_long(&instancelen, value, pos, 10);
2594  if (pos < 0)
2595  goto error;
2596 
2597  /* XXX: If the range is valid but not representable,
2598  * or if it's invalid, then should we refrain from sending
2599  * anything at all? It might pollute the client's cache. */
2600 
2601  if (lastbyte < firstbyte || instancelen < lastbyte) {
2602  warning(0, "WSP: Content-Range '%s' is invalid.",
2603  octstr_get_cstr(value));
2604  return -1;
2605  }
2606 
2607  encoding = octstr_create("");
2608  octstr_append_uintvar(encoding, firstbyte);
2609  octstr_append_uintvar(encoding, instancelen);
2610  wsp_pack_value(packed, encoding);
2611  octstr_destroy(encoding);
2612 
2613  return 0;
2614 
2615 error:
2616  warning(0, "WSP: Cannot parse Content-Range '%s'.",
2617  octstr_get_cstr(value));
2618  return -1;
2619 
2620 warning:
2621  warning(0, "WSP: Cannot encode Content-Range '%s'.",
2622  octstr_get_cstr(value));
2623  return -1;
2624 }
2625 
2627 {
2628  /* The expansion of Content-type-value works out to be
2629  * equivalent to Accept-value. */
2630  return pack_accept(packed, value);
2631 }
2632 
2633 static int pack_expires(Octstr *packed, Octstr *value)
2634 {
2635  int ret;
2636 
2637  ret = wsp_pack_date(packed, value);
2638 
2639  if (ret < 0) {
2640  /* Responses with an invalid Expires header should be treated
2641  as already expired. If we just skip this header, then the client
2642  won't know that. So we encode one with a date far in the past. */
2644  ret = 0;
2645  }
2646 
2647  return ret;
2648 }
2649 
2650 static int pack_if_range(Octstr *packed, Octstr *value)
2651 {
2652  if (octstr_get_char(value, 0) == '"' ||
2653  (octstr_get_char(value, 0) == 'W' &&
2654  octstr_get_char(value, 1) == '/')) {
2655  return wsp_pack_quoted_text(packed, value); /* It's an etag */
2656  } else {
2657  return wsp_pack_date(packed, value);
2658  }
2659 }
2660 
2661 static int pack_pragma(Octstr *packed, Octstr *value)
2662 {
2663  Octstr *nocache;
2664 
2665  nocache = octstr_imm("no-cache");
2666  if (octstr_case_compare(value, nocache) == 0)
2667  wsp_pack_short_integer(packed, WSP_CACHE_CONTROL_NO_CACHE);
2668  else {
2669  Parameter *parm;
2670  Octstr *encoding;
2671 
2672  encoding = octstr_create("");
2673  parm = parm_parse(value);
2674  pack_parameter(encoding, parm);
2675  wsp_pack_value(packed, encoding);
2676  octstr_destroy(encoding);
2677  parm_destroy(parm);
2678  }
2679 
2680  return 0;
2681 }
2682 
2683 static int pack_range(Octstr *packed, Octstr *value)
2684 {
2685  Octstr *bytes = octstr_imm("bytes");
2686  long pos;
2687 
2688  if (octstr_ncompare(value, bytes, octstr_len(bytes)) != 0
2689  || is_token_char(octstr_get_char(value, octstr_len(bytes))))
2690  goto error;
2691 
2692  pos = octstr_len(bytes);
2693  while (isspace(octstr_get_char(value, pos)))
2694  pos++;
2695 
2696  if (octstr_get_char(value, pos) != '=')
2697  goto error;
2698  pos++;
2699 
2700  for (;;) {
2701  /* Discard the whole header if any part of it can't be
2702  * parsed. Probably a partial Range header is worse
2703  * than none at all. */
2704  pos = pack_range_value(packed, value, pos);
2705  if (pos < 0)
2706  goto error;
2707 
2708  while (isspace(octstr_get_char(value, pos)))
2709  pos++;
2710 
2711  if (octstr_get_char(value, pos) != ',')
2712  break;
2713  pos++;
2714 
2715  wsp_pack_short_integer(packed, WSP_HEADER_RANGE);
2716  }
2717 
2718  return 0;
2719 
2720 error:
2721  warning(0, "WSP: Cannot parse 'Range: %s'.",
2722  octstr_get_cstr(value));
2723  return -1;
2724 }
2725 
2726 /* The value is either a HTTP-date or a delta-seconds (integer). */
2727 int wsp_pack_retry_after(Octstr *packed, Octstr *value)
2728 {
2729  Octstr *encoded = NULL;
2730 
2731  encoded = octstr_create("");
2732  if (isdigit(octstr_get_char(value, 0))) {
2734  if (wsp_pack_integer_string(encoded, value) < 0)
2735  goto error;
2736  } else {
2738  if (wsp_pack_date(encoded, value) < 0)
2739  goto error;
2740  }
2741  wsp_pack_value(packed, encoded);
2742 
2743  octstr_destroy(encoded);
2744  return 0;
2745 
2746 error:
2747  octstr_destroy(encoded);
2748  return -1;
2749 }
2750 
2751 
2752 static int convert_rfc2616_warning_to_rfc2068(int warn_code)
2753 {
2754  int i;
2755  struct {
2756  int rfc2616code;
2757  int rfc2068code;
2758  } code_transform[] = {
2759  { 110, 10 }, /* Response is stale */
2760  { 111, 11 }, /* Revalidation failed */
2761  { 112, 12 }, /* Disconnected operation */
2762  { 113, 13 }, /* Heuristic expiration */
2763  { 199, 99 }, /* Miscellaneous warning */
2764  { 214, 14 }, /* Transformation applied */
2765  { 299, 99 }, /* Miscellaneous (persistent) warning */
2766  { -1, -1 }
2767  };
2768 
2769  for (i = 0; code_transform[i].rfc2616code >= 0; i++) {
2770  if (code_transform[i].rfc2616code == warn_code)
2771  return code_transform[i].rfc2068code;
2772  }
2773 
2774  return warn_code; /* conversion failed */
2775 }
2776 
2777 static int pack_warning(Octstr *packed, Octstr *value)
2778 {
2779  long warn_code = -1;
2780  Octstr *warn_agent = NULL;
2781  Octstr *warn_text = NULL;
2782  long pos;
2783  long start;
2784 
2785  pos = octstr_parse_long(&warn_code, value, 0, 10);
2786  if (pos < 0 || warn_code < 0)
2787  goto error;
2788 
2789  if (warn_code > 99) {
2790  /* RFC2068 uses 2-digit codes, and RFC2616 uses 3-digit codes.
2791  * This must be an RFC2616 code. We don't have room in the
2792  * encoding for such codes, so we try to convert it back to
2793  * an RFC2068 code. */
2794  warn_code = convert_rfc2616_warning_to_rfc2068(warn_code);
2795  }
2796 
2797  if (warn_code > MAX_SHORT_INTEGER) {
2798  warning(0, "WSP: Cannot encode warning code %ld.", warn_code);
2799  return -1;
2800  }
2801 
2802  while (isspace(octstr_get_char(value, pos)))
2803  pos++;
2804 
2805  start = pos;
2806  while (pos < octstr_len(value) && !isspace(octstr_get_char(value, pos)))
2807  pos++;
2808 
2809  if (pos > start)
2810  warn_agent = octstr_copy(value, start, pos - start);
2811 
2812  while (isspace(octstr_get_char(value, pos)))
2813  pos++;
2814 
2815  start = pos;
2816  pos += http_header_quoted_string_len(value, pos);
2817  if (pos > start)
2818  warn_text = octstr_copy(value, start, pos - start);
2819 
2820  if (warn_agent == NULL && warn_text == NULL) {
2821  /* Simple encoding */
2822  wsp_pack_short_integer(packed, warn_code);
2823  } else {
2824  /* General encoding */
2825  Octstr *encoding = octstr_create("");
2826 
2827  if (warn_agent == NULL)
2828  warn_agent = octstr_create("");
2829  if (warn_text == NULL)
2830  warn_text = octstr_create("");
2831 
2832  wsp_pack_short_integer(encoding, warn_code);
2833  wsp_pack_text(encoding, warn_agent);
2834  wsp_pack_text(encoding, warn_text);
2835  wsp_pack_value(packed, encoding);
2836  octstr_destroy(encoding);
2837  }
2838 
2839  octstr_destroy(warn_agent);
2840  octstr_destroy(warn_text);
2841  return 0;
2842 
2843 error:
2844  warning(0, "WSP: Cannot parse 'Warning: %s'.",
2845  octstr_get_cstr(value));
2846  octstr_destroy(warn_agent);
2847  octstr_destroy(warn_text);
2848  return -1;
2849 }
2850 
2852 {
2854 
2855  /* Can't use http_header_get_content_type because it
2856  * does not parse all possible parameters. */
2857  content_type = http_header_find_first(headers, "Content-Type");
2858 
2859  if (content_type == NULL) {
2860  warning(0, "WSP: Missing Content-Type header in "
2861  "response, guessing application/octet-stream");
2862  content_type = octstr_create("application/octet-stream");
2863  }
2864  octstr_strip_blanks(content_type);
2865  wsp_pack_content_type(packed, content_type);
2866  octstr_destroy(content_type);
2867 }
2868 
2869 int wsp_pack_list(Octstr *packed, long fieldnum, List *elements, int i)
2870 {
2871  long startpos;
2872  Octstr *element;
2873 
2874  while ((element = gwlist_consume(elements))) {
2875  startpos = octstr_len(packed);
2876 
2877  wsp_pack_short_integer(packed, fieldnum);
2878  if (headerinfo[i].func(packed, element) < 0) {
2879  /* Remove whatever we added */
2880  octstr_delete(packed, startpos,
2881  octstr_len(packed) - startpos);
2882  /* But continue processing elements */
2883  }
2884  octstr_destroy(element);
2885  }
2886  return 0;
2887 }
2888 
2889 static int pack_known_header(Octstr *packed, long fieldnum, Octstr *value)
2890 {
2891  List *elements = NULL;
2892  long startpos;
2893  long i;
2894 
2895  octstr_strip_blanks(value);
2896 
2897  startpos = octstr_len(packed);
2898 
2899  for (i = 0; i < TABLE_SIZE(headerinfo); i++) {
2900  if (headerinfo[i].header == fieldnum)
2901  break;
2902  }
2903 
2904  if (i == TABLE_SIZE(headerinfo)) {
2905  error(0, "WSP: Do not know how to encode header type %ld",
2906  fieldnum);
2907  goto error;
2908  }
2909 
2910  if (headerinfo[i].allows_list == LIST)
2911  elements = http_header_split_value(value);
2912  else if (headerinfo[i].allows_list == BROKEN_LIST)
2913  elements = http_header_split_auth_value(value);
2914  else
2915  elements = NULL;
2916 
2917  if (elements != NULL) {
2918  if (wsp_pack_list(packed, fieldnum, elements, i) < 0)
2919  goto error;
2920  } else {
2921  wsp_pack_short_integer(packed, fieldnum);
2922  debug("wsp",0,"WSP: Known header 0x%04lx, value `%s'.",
2923  fieldnum, octstr_get_cstr(value));
2924  if (headerinfo[i].func(packed, value) < 0)
2925  goto error;
2926  }
2927 
2929  return 0;
2930 
2931 error:
2932  /* Remove whatever we added */
2933  octstr_delete(packed, startpos, octstr_len(packed) - startpos);
2935  return -1;
2936 }
2937 
2939  Octstr *fieldname, Octstr *value)
2940 {
2941  if (!is_token(fieldname)) {
2942  warning(0, "WSP headers: `%s' is not a valid HTTP token.",
2943  octstr_get_cstr(fieldname));
2944  return -1;
2945  }
2946 
2947  /* We have to deal specially with the X-WAP.TOD header, because it
2948  * is the only case of a text-format header defined with a non-text
2949  * field value. */
2950  /* Normally this should be a case-insensitive comparison, but this
2951  * header will only be present if we generated it ourselves in the
2952  * application layer. */
2953  if (octstr_str_compare(fieldname, "X-WAP.TOD") == 0) {
2954  wsp_pack_text(packed, fieldname);
2955  return wsp_pack_date(packed, value);
2956  }
2957 
2958  wsp_pack_text(packed, fieldname);
2959  wsp_pack_text(packed, value);
2960  return 0;
2961 }
2962 
2963 Octstr *wsp_headers_pack(List *headers, int separate_content_type, int wsp_version)
2964 {
2965  Octstr *packed;
2966  long i, len;
2967  int errors;
2968 
2969  packed = octstr_create("");
2970  if (separate_content_type)
2971  wsp_pack_separate_content_type(packed, headers);
2972 
2973  len = gwlist_len(headers);
2974  for (i = 0; i < len; i++) {
2975  Octstr *fieldname;
2976  Octstr *value;
2977  long fieldnum;
2978 
2979  http_header_get(headers, i, &fieldname, &value);
2980  /* XXX we need to obey which WSP encoding-version to use */
2981  /* fieldnum = wsp_string_to_header(fieldname); */
2982  fieldnum = wsp_string_to_versioned_header(fieldname, wsp_version);
2983 
2984  errors = 0;
2985 
2986  if (separate_content_type && fieldnum == WSP_HEADER_CONTENT_TYPE) {
2987  /* already handled */
2988  debug("wsp",0,"WSP: content type already handled.");
2989  } else if (fieldnum < 0) {
2990  if (wsp_pack_application_header(packed, fieldname, value) < 0)
2991  errors = 1;
2992  } else {
2993  if (pack_known_header(packed, fieldnum, value) < 0)
2994  errors = 1;
2995  }
2996 
2997  if (errors)
2998  warning(0, "Skipping header: %s: %s",
2999  octstr_get_cstr(fieldname),
3000  octstr_get_cstr(value));
3001 
3002  octstr_destroy(fieldname);
3003  octstr_destroy(value);
3004  }
3005 
3006  /*
3007  http_header_dump(headers);
3008  octstr_dump(packed, 0);
3009  */
3010 
3011  return packed;
3012 }
3013 
static int pack_range(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2683
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
#define WSP_FIELD_VALUE_DATA
Definition: wsp_headers.h:70
Octstr * key
Definition: wsp_headers.h:106
#define SUFFIX_BYTE_RANGE
Definition: wsp_headers.h:84
#define ABSOLUTE_TIME
Definition: wsp_headers.h:81
static int pack_encoding(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2211
void http_header_get(List *headers, long i, Octstr **name, Octstr **value)
Definition: http.c:2879
static Octstr * unpack_q_value(ParseContext *context)
Definition: wsp_headers.c:270
static int unpack_parameter(ParseContext *context, Octstr *decoded)
Definition: wsp_headers.c:326
void wsp_pack_parameters(Octstr *packed, List *parms)
Definition: wsp_headers.c:1973
static Parameter * parm_create(Octstr *key, Octstr *value)
Definition: wsp_headers.c:1495
void wsp_pack_long_integer(Octstr *packed, unsigned long integer)
Definition: wsp_headers.c:1776
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2863
int parse_peek_char(ParseContext *context)
Definition: parse.c:206
int parse_get_char(ParseContext *context)
Definition: parse.c:218
static int pack_range_value(Octstr *packed, Octstr *value, long pos)
Definition: wsp_headers.c:2258
static int pack_connection(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2205
Definition: parse.c:65
void gwlist_append(List *list, void *item)
Definition: list.c:179
static void pack_quoted_string(Octstr *packed, Octstr *text)
Definition: wsp_headers.c:1637
List * http_header_split_auth_value(Octstr *value)
Definition: http.c:3328
Octstr * wsp_headers_pack(List *headers, int separate_content_type, int wsp_version)
Definition: wsp_headers.c:2963
int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter)
Definition: octstr.c:812
static Octstr * unpack_credentials(ParseContext *context)
Definition: wsp_headers.c:625
#define BROKEN_LIST
Definition: wsp_headers.h:100
long date_parse_http(Octstr *date)
Definition: date.c:147
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1502
static Octstr * unpack_encoding_version(ParseContext *context)
Definition: wsp_headers.c:309
static Octstr * unpack_accept_language_general_form(ParseContext *context)
Definition: wsp_headers.c:590
long gwlist_len(List *list)
Definition: list.c:166
#define WSP_QUOTE
Definition: wsp_headers.h:74
static Octstr * unpack_challenge(ParseContext *context)
Definition: wsp_headers.c:719
void * gwlist_get(List *list, long pos)
Definition: list.c:292
static int is_token_char(int c)
Definition: wsp_headers.c:1676
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1515
#define BYTE_RANGE
Definition: wsp_headers.h:83
static void unpack_optional_q_value(ParseContext *context, Octstr *decoded)
Definition: wsp_headers.c:478
int type
Definition: smsc_cimd2.c:215
#define BASIC_AUTHENTICATION
Definition: wsp_headers.h:80
static int is_token(Octstr *token)
Definition: wsp_headers.c:1682
void octstr_binary_to_base64(Octstr *ostr)
Definition: octstr.c:540
void wsp_unpack_all_parameters(ParseContext *context, Octstr *decoded)
Definition: wsp_headers.c:443
Octstr * value
Definition: wsp_headers.h:107
void wsp_unpack_app_header(List *unpacked, ParseContext *context)
Definition: wsp_headers.c:1311
static int pack_known_header(Octstr *packed, long fieldnum, Octstr *value)
Definition: wsp_headers.c:2889
Octstr * wsp_unpack_accept_general_form(ParseContext *context)
Definition: wsp_headers.c:513
static int pack_content_range(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2555
static Octstr * unpack_warning_value(ParseContext *context)
Definition: wsp_headers.c:984
void wsp_pack_value(Octstr *packed, Octstr *encoded)
Definition: wsp_headers.c:1761
static int pack_method(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2241
long http_header_quoted_string_len(Octstr *header, long start)
Definition: http.c:3270
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
Definition: octstr.c:1459
void octstr_strip_blanks(Octstr *text)
Definition: octstr.c:1344
static int pack_expires(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2633
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
void parse_skip_to_limit(ParseContext *context)
Definition: parse.c:180
static int pack_transfer_encoding(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2318
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
static Octstr * unpack_content_range(ParseContext *context)
Definition: wsp_headers.c:759
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1010
void wsp_pack_short_integer(Octstr *packed, unsigned long integer)
Definition: wsp_headers.c:1800
Octstr * charset
Definition: test_ota.c:68
static Octstr * unpack_retry_after(ParseContext *context)
Definition: wsp_headers.c:909
int wsp_pack_content_type(Octstr *packed, Octstr *value)
Definition: wsp_headers.c:2626
static Octstr * unpack_field_name(ParseContext *context)
Definition: wsp_headers.c:792
void wsp_pack_separate_content_type(Octstr *packed, List *headers)
Definition: wsp_headers.c:2851
List * wsp_strip_parameters(Octstr *value)
Definition: wsp_headers.c:1553
int wsp_pack_application_header(Octstr *packed, Octstr *fieldname, Octstr *value)
Definition: wsp_headers.c:2938
#define WSP_FIELD_VALUE_NONE
Definition: wsp_headers.h:71
static int parse_qvalue(Octstr *value)
Definition: wsp_headers.c:1690
static int pack_qvalue(Octstr *packed, int qvalue)
Definition: wsp_headers.c:1744
int parse_pop_limit(ParseContext *context)
Definition: parse.c:142
unsigned char * password
Definition: test_cimd2.c:100
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
Octstr * wsp_unpack_integer_value(ParseContext *context)
Definition: wsp_headers.c:214
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1301
int token
Definition: wslexer.c:157
void gwlist_delete(List *list, long pos, long count)
Definition: list.c:232
void parm_destroy_item(void *parm)
Definition: wsp_headers.c:1515
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
static long unpack_multi_octet_integer(ParseContext *context, long len)
Definition: wsp_headers.c:151
static Octstr * unpack_range_value(ParseContext *context)
Definition: wsp_headers.c:941
static Octstr * proxy_unpack_credentials(ParseContext *context)
Definition: wsp_headers.c:679
char * text
Definition: smsc_cimd2.c:921
List * http_create_empty_headers(void)
Definition: http.c:2849
#define TABLE_SIZE(table)
Definition: wsp_headers.h:102
#define RELATIVE_TIME
Definition: wsp_headers.h:82
int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
Definition: octstr.c:950
Octstr * parse_get_octets(ParseContext *context, long length)
Definition: parse.c:230
#define octstr_duplicate(ostr)
Definition: octstr.h:187
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
#define http_header_find_first(headers, name)
Definition: http.h:592
List * http_header_split_value(Octstr *value)
Definition: http.c:3294
static int pack_challenge(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2014
int wsp_pack_quoted_text(Octstr *packed, Octstr *text)
Definition: wsp_headers.c:1627
int gw_isdigit(int c)
Definition: utils.c:988
int octstr_case_compare(const Octstr *os1, const Octstr *os2)
Definition: octstr.c:901
void parse_set_error(ParseContext *context)
Definition: parse.c:114
void warning(int err, const char *fmt,...)
Definition: log.c:624
static int pack_accept_language(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2417
Definition: seewbmp.c:154
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:334
static int pack_cache_control(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2451
int wsp_pack_list(Octstr *packed, long fieldnum, List *elements, int i)
Definition: wsp_headers.c:2869
gw_assert(wtls_machine->packet_to_send!=NULL)
static int pack_accept_charset(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2355
const char * content_type
Definition: fakewap.c:249
static int pack_credentials(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2118
static int pack_content_disposition(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2526
static void unpack_broken_parameters(ParseContext *context, Octstr *decoded)
Definition: wsp_headers.c:455
void octstr_base64_to_binary(Octstr *ostr)
Definition: octstr.c:661
int parse_limit(ParseContext *context, long length)
Definition: parse.c:121
static int convert_rfc2616_warning_to_rfc2068(int warn_code)
Definition: wsp_headers.c:2752
#define LONG_AGO_VALUE
Definition: wsp_headers.h:90
int wsp_field_value(ParseContext *context, int *well_known_value)
Definition: wsp_headers.c:107
int wsp_pack_date(Octstr *packed, Octstr *value)
Definition: wsp_headers.c:2186
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
static Parameter * parm_parse(Octstr *value)
Definition: wsp_headers.c:1520
void wsp_pack_integer_value(Octstr *packed, unsigned long integer)
Definition: wsp_headers.c:1807
static int pack_md5(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:1990
void octstr_append_uintvar(Octstr *ostr, unsigned long value)
Definition: octstr.c:1929
int parse_skip(ParseContext *context, long count)
Definition: parse.c:166
void octstr_append_decimal(Octstr *ostr, long value)
Definition: octstr.c:1974
#define MAX_SHORT_INTEGER
Definition: wsp_headers.h:77
void parse_context_destroy(ParseContext *context)
Definition: parse.c:88
Definition: octstr.c:118
#define WSP_FIELD_VALUE_NUL_STRING
Definition: wsp_headers.h:68
void * gwlist_consume(List *list)
Definition: list.c:427
static void pack_parameter(Octstr *packed, Parameter *parm)
Definition: wsp_headers.c:1888
static int pack_warning(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2777
List * wsp_headers_unpack(Octstr *headers, int content_type_present)
Definition: wsp_headers.c:1331
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
#define panic
Definition: log.h:87
static int pack_language(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2226
void wsp_skip_field_value(ParseContext *context)
Definition: wsp_headers.c:138
int octstr_str_compare(const Octstr *ostr, const char *str)
Definition: octstr.c:971
int wsp_pack_version_value(Octstr *packed, Octstr *version)
Definition: wsp_headers.c:1848
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:747
Octstr * wsp_unpack_date_value(ParseContext *context)
Definition: wsp_headers.c:492
Octstr * parse_get_nul_string(ParseContext *context)
Definition: parse.c:263
int wsp_pack_integer_string(Octstr *packed, Octstr *value)
Definition: wsp_headers.c:1815
int wsp_pack_text(Octstr *packed, Octstr *text)
Definition: wsp_headers.c:1615
#define gwlist_create()
Definition: list.h:136
static Octstr * unpack_disposition(ParseContext *context)
Definition: wsp_headers.c:925
#define LIST
Definition: wsp_headers.h:94
Octstr * wsp_unpack_accept_charset_general_form(ParseContext *context)
Definition: wsp_headers.c:557
unsigned long parse_get_uintvar(ParseContext *context)
Definition: parse.c:246
Octstr * date_format_http(unsigned long unixtime)
Definition: date.c:89
int wsp_pack_constrained_value(Octstr *packed, Octstr *text, long value)
Definition: wsp_headers.c:1879
static int is_separator_char(int c)
Definition: wsp_headers.c:1647
void wsp_unpack_well_known_field(List *unpacked, int field_type, ParseContext *context)
Definition: wsp_headers.c:1030
static int get_qvalue(List *parms, int default_qvalue)
Definition: wsp_headers.c:1725
static int pack_field_name(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2217
int parse_error(ParseContext *context)
Definition: parse.c:100
#define WSP_FIELD_VALUE_ENCODED
Definition: wsp_headers.h:69
Octstr * wsp_unpack_version_value(long value)
Definition: wsp_headers.c:291
static int pack_accept_encoding(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2393
int wsp_pack_retry_after(Octstr *packed, Octstr *value)
Definition: wsp_headers.c:2727
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
static int pack_uri(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:1984
static int pack_if_range(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2650
void octstr_set_char(Octstr *ostr, long pos, int ch)
Definition: octstr.c:413
static Octstr * convert_q_value(int q)
Definition: wsp_headers.c:236
void parse_clear_error(ParseContext *context)
Definition: parse.c:107
Definition: wsp.h:72
ParseContext * parse_context_create(Octstr *str)
Definition: parse.c:74
static int pack_accept(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2325
Definition: list.c:102
static Octstr * unpack_cache_directive(ParseContext *context)
Definition: wsp_headers.c:824
static void parm_destroy(Parameter *parm)
Definition: wsp_headers.c:1505
static int pack_range_unit(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2250
static int pack_pragma(Octstr *packet, Octstr *value)
Definition: wsp_headers.c:2661
static int start
long parse_octets_left(ParseContext *context)
Definition: parse.c:159
int wsp_secondary_field_value(ParseContext *context, long *result)
Definition: wsp_headers.c:183
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.