00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 #include <string.h>
00085 #include <limits.h>
00086 #include <ctype.h>
00087
00088 #include "gwlib/gwlib.h"
00089 #include "wsp.h"
00090 #include "wsp_headers.h"
00091 #include "wsp_strings.h"
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 int wsp_field_value(ParseContext *context, int *well_known_value)
00108 {
00109 int val;
00110 unsigned long len;
00111
00112 val = parse_get_char(context);
00113 if (val > 0 && val < 31) {
00114 *well_known_value = -1;
00115 parse_limit(context, val);
00116 return WSP_FIELD_VALUE_DATA;
00117 } else if (val == 31) {
00118 *well_known_value = -1;
00119 len = parse_get_uintvar(context);
00120 parse_limit(context, len);
00121 return WSP_FIELD_VALUE_DATA;
00122 } else if (val > 127) {
00123 *well_known_value = val - 128;
00124 return WSP_FIELD_VALUE_ENCODED;
00125 } else if (val == WSP_QUOTE || val == '"') {
00126 *well_known_value = -1;
00127
00128 return WSP_FIELD_VALUE_NUL_STRING;
00129 } else {
00130 *well_known_value = -1;
00131
00132 parse_skip(context, -1);
00133 return WSP_FIELD_VALUE_NUL_STRING;
00134 }
00135 }
00136
00137
00138 void wsp_skip_field_value(ParseContext *context)
00139 {
00140 int val;
00141 int ret;
00142
00143 ret = wsp_field_value(context, &val);
00144 if (ret == WSP_FIELD_VALUE_DATA) {
00145 parse_skip_to_limit(context);
00146 parse_pop_limit(context);
00147 }
00148 }
00149
00150
00151 static long unpack_multi_octet_integer(ParseContext *context, long len)
00152 {
00153 long val = 0;
00154
00155 if (len > (long) sizeof(val) || len < 0)
00156 return -1;
00157
00158 while (len > 0) {
00159 val = val * 256 + parse_get_char(context);
00160 len--;
00161 }
00162
00163 if (parse_error(context))
00164 return -1;
00165
00166 return val;
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 int wsp_secondary_field_value(ParseContext *context, long *result)
00184 {
00185 int val;
00186 long length;
00187
00188 val = parse_get_char(context);
00189 if (val == 0) {
00190 *result = 0;
00191 return WSP_FIELD_VALUE_NONE;
00192 } else if (val > 0 && val < 31) {
00193 *result = unpack_multi_octet_integer(context, val);
00194 return WSP_FIELD_VALUE_ENCODED;
00195 } else if (val == 31) {
00196 length = parse_get_uintvar(context);
00197 *result = unpack_multi_octet_integer(context, length);
00198 return WSP_FIELD_VALUE_ENCODED;
00199 } else if (val > 127) {
00200 *result = val - 128;
00201 return WSP_FIELD_VALUE_ENCODED;
00202 } else if (val == WSP_QUOTE) {
00203 *result = -1;
00204 return WSP_FIELD_VALUE_NUL_STRING;
00205 } else {
00206 *result = -1;
00207
00208 parse_skip(context, -1);
00209 return WSP_FIELD_VALUE_NUL_STRING;
00210 }
00211 }
00212
00213
00214 Octstr *wsp_unpack_integer_value(ParseContext *context)
00215 {
00216 Octstr *decoded;
00217 unsigned long value;
00218 int val;
00219
00220 val = parse_get_char(context);
00221 if (val < 31) {
00222 value = unpack_multi_octet_integer(context, val);
00223 } else if (val > 127) {
00224 value = val - 128;
00225 } else {
00226 warning(0, "WSP headers: bad integer-value.");
00227 return NULL;
00228 }
00229
00230 decoded = octstr_create("");
00231 octstr_append_decimal(decoded, value);
00232 return decoded;
00233 }
00234
00235
00236 static Octstr *convert_q_value(int q)
00237 {
00238 Octstr *result = NULL;
00239
00240
00241
00242
00243
00244 if (q >= 1 && q <= 100) {
00245 q = q - 1;
00246 result = octstr_create("0.");
00247 octstr_append_char(result, (q / 10) + '0');
00248 if (q % 10 > 0)
00249 octstr_append_char(result, (q % 10) + '0');
00250 return result;
00251 }
00252
00253
00254
00255 if (q > 100 && q <= 1000) {
00256 q = q - 100;
00257 result = octstr_create("0.");
00258 octstr_append_char(result, (q / 100) + '0');
00259 if (q % 100 > 0)
00260 octstr_append_char(result, (q / 10 % 10) + '0');
00261 if (q % 10 > 0)
00262 octstr_append_char(result, (q % 10) + '0');
00263 return result;
00264 }
00265
00266 return NULL;
00267 }
00268
00269
00270 static Octstr *unpack_q_value(ParseContext *context)
00271 {
00272 int c, c2;
00273
00274 c = parse_get_char(context);
00275 if (c < 0)
00276 return NULL;
00277
00278 if (c & 0x80) {
00279 c2 = parse_get_char(context);
00280 if (c2 < 0 || (c2 & 0x80))
00281 return NULL;
00282 c = ((c & 0x7f) << 8) + c2;
00283 }
00284
00285 return convert_q_value(c);
00286 }
00287
00288
00289
00290
00291 Octstr *wsp_unpack_version_value(long value)
00292 {
00293 Octstr *result;
00294 int major, minor;
00295
00296 major = ((value >> 4) & 0x7);
00297 minor = (value & 0xf);
00298
00299 result = octstr_create("");
00300 octstr_append_char(result, major + '0');
00301 if (minor != 15) {
00302 octstr_append_char(result, '.');
00303 octstr_append_decimal(result, minor);
00304 }
00305
00306 return result;
00307 }
00308
00309 static Octstr *unpack_encoding_version(ParseContext *context)
00310 {
00311 int ch;
00312
00313 ch = parse_get_char(context);
00314 if (ch < 128) {
00315 warning(0, "WSP: bad Encoding-Version value");
00316 return NULL;
00317 }
00318
00319 return wsp_unpack_version_value(((long) ch) - 128);
00320 }
00321
00322
00323
00324
00325
00326 static int unpack_parameter(ParseContext *context, Octstr *decoded)
00327 {
00328 Octstr *parm = NULL;
00329 Octstr *value = NULL;
00330 int ret;
00331 long type;
00332 long val;
00333
00334 ret = wsp_secondary_field_value(context, &type);
00335 if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
00336 warning(0, "bad parameter");
00337 goto error;
00338 }
00339
00340 if (ret == WSP_FIELD_VALUE_ENCODED) {
00341
00342 parm = wsp_parameter_to_string(type);
00343 if (!parm)
00344 warning(0, "Unknown parameter %02lx.", type);
00345 } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
00346
00347 parm = parse_get_nul_string(context);
00348 if (!parm)
00349 warning(0, "Format error in parameter.");
00350 type = -1;
00351
00352
00353
00354 } else {
00355 panic(0, "Unknown secondary field value type %d.", ret);
00356 }
00357
00358 if (type == 0x00)
00359 value = unpack_q_value(context);
00360 else {
00361 ret = wsp_secondary_field_value(context, &val);
00362 if (parse_error(context)) {
00363 warning(0, "bad parameter value");
00364 goto error;
00365 }
00366
00367 if (ret == WSP_FIELD_VALUE_ENCODED) {
00368 switch (type) {
00369 case -1:
00370 case 3:
00371 case 8:
00372 value = octstr_create("");
00373 octstr_append_decimal(value, val);
00374 break;
00375 case 0:
00376 gw_assert(0);
00377 break;
00378 case 1:
00379 value = wsp_charset_to_string(val);
00380 if (!value)
00381 warning(0, "Unknown charset %04lx.", val);
00382 break;
00383 case 2:
00384 value = wsp_unpack_version_value(val);
00385 break;
00386 case 5:
00387 case 6:
00388 warning(0, "Text-string parameter with integer encoding");
00389 break;
00390 case 7:
00391 value = wsp_header_to_string(val);
00392 if (!value)
00393 warning(0, "Unknown differences header %02lx.", val);
00394 break;
00395 default:
00396 warning(0, "Unknown parameter encoding %02lx.",
00397 type);
00398 break;
00399 }
00400 } else if (ret == WSP_FIELD_VALUE_NONE) {
00401 value = octstr_create("");
00402 } else {
00403 gw_assert(ret == WSP_FIELD_VALUE_NUL_STRING);
00404
00405 value = parse_get_nul_string(context);
00406 if (!value)
00407 warning(0, "Format error in parameter value.");
00408 else {
00409 if (octstr_get_char(value, 0) == '"') {
00410
00411 octstr_append_char(value, '"');
00412 } else {
00413 octstr_insert(value, octstr_imm("\""), 0);
00414 octstr_append_char(value, '"');
00415 }
00416 }
00417 }
00418 }
00419
00420 if (!parm || !value) {
00421 warning(0, "Skipping parameters");
00422 goto error;
00423 }
00424
00425 octstr_append(decoded, octstr_imm("; "));
00426 octstr_append(decoded, parm);
00427 if (octstr_len(value) > 0) {
00428 octstr_append_char(decoded, '=');
00429 octstr_append(decoded, value);
00430 }
00431 octstr_destroy(parm);
00432 octstr_destroy(value);
00433 return 0;
00434
00435 error:
00436 parse_skip_to_limit(context);
00437 octstr_destroy(parm);
00438 octstr_destroy(value);
00439 parse_set_error(context);
00440 return -1;
00441 }
00442
00443 void wsp_unpack_all_parameters(ParseContext *context, Octstr *decoded)
00444 {
00445 int ret = 0;
00446
00447 while (ret >= 0 && !parse_error(context) &&
00448 parse_octets_left(context) > 0) {
00449 ret = unpack_parameter(context, decoded);
00450 }
00451 }
00452
00453
00454
00455 static void unpack_broken_parameters(ParseContext *context, Octstr *decoded)
00456 {
00457 int ret = 0;
00458 int first = 1;
00459 long pos;
00460
00461 while (ret >= 0 && !parse_error(context) &&
00462 parse_octets_left(context) > 0) {
00463 pos = octstr_len(decoded);
00464 ret = unpack_parameter(context, decoded);
00465 if (ret >= 0) {
00466 if (first) {
00467
00468 octstr_delete(decoded, pos, 1);
00469 first = 0;
00470 } else {
00471
00472 octstr_set_char(decoded, pos, first ? ' ' : ',');
00473 }
00474 }
00475 }
00476 }
00477
00478 static void unpack_optional_q_value(ParseContext *context, Octstr *decoded)
00479 {
00480 if (parse_octets_left(context) > 0) {
00481 Octstr *qval = unpack_q_value(context);
00482 if (qval) {
00483 octstr_append(decoded, octstr_imm("; q="));
00484 octstr_append(decoded, qval);
00485 octstr_destroy(qval);
00486 } else
00487 warning(0, "Bad q-value");
00488 }
00489 }
00490
00491
00492 Octstr *wsp_unpack_date_value(ParseContext *context)
00493 {
00494 unsigned long timeval;
00495 int length;
00496
00497 length = parse_get_char(context);
00498 if (length > 30) {
00499 warning(0, "WSP headers: bad date-value.");
00500 return NULL;
00501 }
00502
00503 timeval = unpack_multi_octet_integer(context, length);
00504 if (timeval < 0) {
00505 warning(0, "WSP headers: cannot unpack date-value.");
00506 return NULL;
00507 }
00508
00509 return date_format_http(timeval);
00510 }
00511
00512
00513 Octstr *wsp_unpack_accept_general_form(ParseContext *context)
00514 {
00515 Octstr *decoded = NULL;
00516 int ret;
00517 long val;
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 ret = wsp_secondary_field_value(context, &val);
00531 if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
00532 warning(0, "bad media-range or media-type");
00533 return NULL;
00534 }
00535
00536 if (ret == WSP_FIELD_VALUE_ENCODED) {
00537 decoded = wsp_content_type_to_string(val);
00538 if (!decoded) {
00539 warning(0, "Unknown content type 0x%02lx.", val);
00540 return NULL;
00541 }
00542 } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
00543 decoded = parse_get_nul_string(context);
00544 if (!decoded) {
00545 warning(0, "Format error in content type");
00546 return NULL;
00547 }
00548 } else {
00549 panic(0, "Unknown secondary field value type %d.", ret);
00550 }
00551
00552 wsp_unpack_all_parameters(context, decoded);
00553 return decoded;
00554 }
00555
00556
00557 Octstr *wsp_unpack_accept_charset_general_form(ParseContext *context)
00558 {
00559 Octstr *decoded = NULL;
00560 int ret;
00561 long val;
00562
00563 ret = wsp_secondary_field_value(context, &val);
00564 if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
00565 warning(0, "Bad accept-charset-general-form");
00566 return NULL;
00567 }
00568
00569 if (ret == WSP_FIELD_VALUE_ENCODED) {
00570 decoded = wsp_charset_to_string(val);
00571 if (!decoded) {
00572 warning(0, "Unknown character set %04lx.", val);
00573 return NULL;
00574 }
00575 } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
00576 decoded = parse_get_nul_string(context);
00577 if (!decoded) {
00578 warning(0, "Format error in accept-charset");
00579 return NULL;
00580 }
00581 } else {
00582 panic(0, "Unknown secondary field value type %d.", ret);
00583 }
00584
00585 unpack_optional_q_value(context, decoded);
00586 return decoded;
00587 }
00588
00589
00590 static Octstr *unpack_accept_language_general_form(ParseContext *context)
00591 {
00592 Octstr *decoded = NULL;
00593 int ret;
00594 long val;
00595
00596 ret = wsp_secondary_field_value(context, &val);
00597 if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) {
00598 warning(0, "Bad accept-language-general-form");
00599 return NULL;
00600 }
00601
00602 if (ret == WSP_FIELD_VALUE_ENCODED) {
00603
00604
00605 decoded = wsp_language_to_string(val);
00606 if (!decoded) {
00607 warning(0, "Unknown language %02lx.", val);
00608 return NULL;
00609 }
00610 } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
00611 decoded = parse_get_nul_string(context);
00612 if (!decoded) {
00613 warning(0, "Format error in accept-language");
00614 return NULL;
00615 }
00616 } else {
00617 panic(0, "Unknown secondary field value type %d.", ret);
00618 }
00619
00620 unpack_optional_q_value(context, decoded);
00621 return decoded;
00622 }
00623
00624
00625 static Octstr *unpack_credentials(ParseContext *context)
00626 {
00627 Octstr *decoded = NULL;
00628 int val;
00629
00630 val = parse_peek_char(context);
00631
00632 if (val == BASIC_AUTHENTICATION) {
00633 Octstr *userid, *password;
00634
00635 parse_skip(context, 1);
00636
00637 userid = parse_get_nul_string(context);
00638 password = parse_get_nul_string(context);
00639
00640 if (parse_error(context)) {
00641 octstr_destroy(userid);
00642 octstr_destroy(password);
00643 } else {
00644
00645 decoded = octstr_duplicate(userid);
00646 octstr_append_char(decoded, ':');
00647 octstr_append(decoded, password);
00648
00649
00650
00651
00652
00653 octstr_binary_to_base64(decoded);
00654
00655
00656 octstr_delete(decoded, octstr_len(decoded) - 2, 2);
00657
00658 octstr_insert_data(decoded, 0, "Basic ", 6);
00659
00660 octstr_destroy(userid);
00661 octstr_destroy(password);
00662 }
00663 } else if (val >= 32 && val < 128) {
00664
00665 decoded = parse_get_nul_string(context);
00666 if (decoded)
00667 unpack_broken_parameters(context, decoded);
00668 }
00669
00670 if (!decoded)
00671 warning(0, "Cannot parse credentials.");
00672
00673 return decoded;
00674 }
00675
00676
00677
00678
00679 static Octstr *proxy_unpack_credentials(ParseContext *context)
00680 {
00681 Octstr *decoded = NULL;
00682 int val;
00683
00684 val = parse_peek_char(context);
00685
00686 if (val == BASIC_AUTHENTICATION) {
00687 Octstr *userid, *password;
00688
00689 parse_skip(context, 1);
00690
00691 userid = parse_get_nul_string(context);
00692 password = parse_get_nul_string(context);
00693
00694 if (parse_error(context)) {
00695 octstr_destroy(userid);
00696 octstr_destroy(password);
00697 } else {
00698
00699 decoded = octstr_duplicate(userid);
00700 octstr_append_char(decoded, ':');
00701 octstr_append(decoded, password);
00702 octstr_destroy(userid);
00703 octstr_destroy(password);
00704 }
00705 } else if (val >= 32 && val < 128) {
00706
00707 decoded = parse_get_nul_string(context);
00708 if (decoded)
00709 unpack_broken_parameters(context, decoded);
00710 }
00711
00712 if (!decoded)
00713 warning(0, "Cannot parse credentials.");
00714
00715 return decoded;
00716 }
00717
00718
00719 static Octstr *unpack_challenge(ParseContext *context)
00720 {
00721 Octstr *decoded = NULL;
00722 Octstr *realm_value = NULL;
00723 int val;
00724
00725 val = parse_peek_char(context);
00726 if (val == BASIC_AUTHENTICATION) {
00727 parse_skip(context, 1);
00728 realm_value = parse_get_nul_string(context);
00729 if (realm_value) {
00730 decoded = octstr_create("Basic realm=\"");
00731 octstr_append(decoded, realm_value);
00732 octstr_append_char(decoded, '"');
00733 }
00734 } else if (val >= 32 && val < 128) {
00735
00736 decoded = parse_get_nul_string(context);
00737 realm_value = parse_get_nul_string(context);
00738 if (decoded && realm_value) {
00739 octstr_append(decoded,
00740 octstr_imm(" realm=\""));
00741 octstr_append(decoded, realm_value);
00742 octstr_append_char(decoded, '"');
00743 if (parse_octets_left(context) > 0) {
00744
00745 octstr_append_char(decoded, ',');
00746 }
00747 unpack_broken_parameters(context, decoded);
00748 }
00749 }
00750
00751 if (!decoded)
00752 warning(0, "Cannot parse challenge.");
00753
00754 octstr_destroy(realm_value);
00755 return decoded;
00756 }
00757
00758
00759 static Octstr *unpack_content_range(ParseContext *context)
00760 {
00761
00762
00763
00764 warning(0, "Decoding of content-range not supported");
00765 return NULL;
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789 }
00790
00791
00792 static Octstr *unpack_field_name(ParseContext *context)
00793 {
00794 Octstr *decoded = NULL;
00795 int ret;
00796 int val;
00797
00798 ret = wsp_field_value(context, &val);
00799 if (parse_error(context) || ret == WSP_FIELD_VALUE_DATA) {
00800 warning(0, "Bad field-name encoding");
00801 return NULL;
00802 }
00803
00804 if (ret == WSP_FIELD_VALUE_ENCODED) {
00805 decoded = wsp_header_to_string(val);
00806 if (!decoded) {
00807 warning(0, "Unknown field-name 0x%02x.", val);
00808 return NULL;
00809 }
00810 } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
00811 decoded = parse_get_nul_string(context);
00812 if (!decoded) {
00813 warning(0, "Bad field-name encoding");
00814 return NULL;
00815 }
00816 } else {
00817 panic(0, "Unknown field value type %d.", ret);
00818 }
00819
00820 return decoded;
00821 }
00822
00823
00824 static Octstr *unpack_cache_directive(ParseContext *context)
00825 {
00826 Octstr *decoded = NULL;
00827 int ret;
00828 int val;
00829
00830 ret = wsp_field_value(context, &val);
00831 if (parse_error(context) || ret == WSP_FIELD_VALUE_DATA) {
00832 warning(0, "Bad cache-directive");
00833 goto error;
00834 }
00835
00836 if (ret == WSP_FIELD_VALUE_ENCODED) {
00837 decoded = wsp_cache_control_to_string(val);
00838 if (!decoded) {
00839 warning(0, "Bad cache-directive 0x%02x.", val);
00840 goto error;
00841 }
00842 octstr_append_char(decoded, '=');
00843 switch (val) {
00844 case WSP_CACHE_CONTROL_NO_CACHE:
00845 case WSP_CACHE_CONTROL_PRIVATE:
00846 if (parse_octets_left(context) == 0) {
00847 warning(0, "Too short cache-directive");
00848 goto error;
00849 }
00850 octstr_append_char(decoded, '"');
00851 do {
00852 Octstr *fieldname = unpack_field_name(context);
00853 if (!fieldname) {
00854 warning(0, "Bad field name in cache directive");
00855 goto error;
00856 }
00857 octstr_append(decoded, fieldname);
00858 octstr_destroy(fieldname);
00859 if (parse_octets_left(context) > 0) {
00860 octstr_append_char(decoded, ',');
00861 octstr_append_char(decoded, ' ');
00862 }
00863 } while (parse_octets_left(context) > 0 &&
00864 !parse_error(context));
00865 octstr_append_char(decoded, '"');
00866 break;
00867 case WSP_CACHE_CONTROL_MAX_AGE:
00868 case WSP_CACHE_CONTROL_MAX_STALE:
00869 case WSP_CACHE_CONTROL_MIN_FRESH:
00870 {
00871 Octstr *seconds;
00872 seconds = wsp_unpack_integer_value(context);
00873 if (!seconds) {
00874 warning(0, "Bad integer value in cache directive");
00875 goto error;
00876 }
00877 octstr_append(decoded, seconds);
00878 octstr_destroy(seconds);
00879 }
00880 break;
00881 default:
00882 warning(0, "Unexpected value 0x%02x in cache directive.", val);
00883 break;
00884 }
00885 } else if (ret == WSP_FIELD_VALUE_NUL_STRING) {
00886
00887
00888
00889
00890 decoded = parse_get_nul_string(context);
00891 if (!decoded) {
00892 warning(0, "Format error in cache-control.");
00893 return NULL;
00894 }
00895
00896 unpack_parameter(context, decoded);
00897 } else {
00898 panic(0, "Unknown field value type %d.", ret);
00899 }
00900
00901 return decoded;
00902
00903 error:
00904 octstr_destroy(decoded);
00905 return NULL;
00906 }
00907
00908
00909 static Octstr *unpack_retry_after(ParseContext *context)
00910 {
00911 int selector;
00912
00913 selector = parse_get_char(context);
00914 if (selector == ABSOLUTE_TIME) {
00915 return wsp_unpack_date_value(context);
00916 } else if (selector == RELATIVE_TIME) {
00917 return wsp_unpack_integer_value(context);
00918 } else {
00919 warning(0, "Cannot parse retry-after value.");
00920 return NULL;
00921 }
00922 }
00923
00924
00925 static Octstr *unpack_disposition(ParseContext *context)
00926 {
00927 Octstr *decoded = NULL;
00928 int selector;
00929
00930 selector = parse_get_char(context) - 128;
00931 decoded = wsp_disposition_to_string(selector);
00932 if (!decoded) {
00933 warning(0, "Cannot parse content-disposition value.");
00934 return NULL;
00935 }
00936 wsp_unpack_all_parameters(context, decoded);
00937 return decoded;
00938 }
00939
00940
00941 static Octstr *unpack_range_value(ParseContext *context)
00942 {
00943 Octstr *decoded = NULL;
00944 int selector;
00945 unsigned long first_byte_pos, last_byte_pos, suffix_length;
00946
00947 selector = parse_get_char(context);
00948 if (selector == BYTE_RANGE) {
00949 first_byte_pos = parse_get_uintvar(context);
00950 if (parse_error(context))
00951 goto error;
00952
00953 decoded = octstr_create("bytes = ");
00954 octstr_append_decimal(decoded, first_byte_pos);
00955 octstr_append_char(decoded, '-');
00956
00957 last_byte_pos = parse_get_uintvar(context);
00958 if (parse_error(context)) {
00959
00960 parse_clear_error(context);
00961 } else {
00962 octstr_append_decimal(decoded, last_byte_pos);
00963 }
00964 } else if (selector == SUFFIX_BYTE_RANGE) {
00965 suffix_length = parse_get_uintvar(context);
00966 if (parse_error(context))
00967 goto error;
00968
00969 decoded = octstr_create("bytes = -");
00970 octstr_append_decimal(decoded, suffix_length);
00971 } else {
00972 goto error;
00973 }
00974
00975 return decoded;
00976
00977 error:
00978 warning(0, "Bad format for range-value.");
00979 octstr_destroy(decoded);
00980 return NULL;
00981 }
00982
00983
00984 static Octstr *unpack_warning_value(ParseContext *context)
00985 {
00986 Octstr *decoded = NULL;
00987 Octstr *warn_code = NULL;
00988 Octstr *warn_agent = NULL;
00989 Octstr *warn_text = NULL;
00990 unsigned char quote = '"';
00991
00992 warn_code = wsp_unpack_integer_value(context);
00993
00994 warn_agent = parse_get_nul_string(context);
00995 if (warn_agent && octstr_get_char(warn_agent, 0) == WSP_QUOTE)
00996 octstr_delete(warn_agent, 0, 1);
00997
00998 warn_text = parse_get_nul_string(context);
00999 if (warn_text && octstr_get_char(warn_text, 0) == WSP_QUOTE)
01000 octstr_delete(warn_text, 0, 1);
01001 if (octstr_get_char(warn_text, 0) != quote)
01002 octstr_insert_data(warn_text, 0, (char *)"e, 1);
01003 if (octstr_get_char(warn_text, octstr_len(warn_text) - 1) != quote)
01004 octstr_append_char(warn_text, quote);
01005
01006 if (parse_error(context) || !warn_agent || !warn_text)
01007 goto error;
01008
01009 decoded = octstr_create("");
01010 octstr_append(decoded, warn_code);
01011 octstr_append_char(decoded, ' ');
01012 octstr_append(decoded, warn_agent);
01013 octstr_append_char(decoded, ' ');
01014 octstr_append(decoded, warn_text);
01015
01016 octstr_destroy(warn_agent);
01017 octstr_destroy(warn_code);
01018 octstr_destroy(warn_text);
01019 return decoded;
01020
01021 error:
01022 warning(0, "Bad format for warning-value.");
01023 octstr_destroy(warn_agent);
01024 octstr_destroy(warn_code);
01025 octstr_destroy(warn_text);
01026 octstr_destroy(decoded);
01027 return NULL;
01028 }
01029
01030 void wsp_unpack_well_known_field(List *unpacked, int field_type,
01031 ParseContext *context)
01032 {
01033 int val, ret;
01034 unsigned char *headername = NULL;
01035 unsigned char *ch = NULL;
01036 Octstr *decoded = NULL;
01037
01038 ret = wsp_field_value(context, &val);
01039 if (parse_error(context)) {
01040 warning(0, "Faulty header, skipping remaining headers.");
01041 parse_skip_to_limit(context);
01042 return;
01043 }
01044
01045 headername = wsp_header_to_cstr(field_type);
01046
01047
01048
01049
01050
01051
01052
01053 if (ret == WSP_FIELD_VALUE_NUL_STRING) {
01054
01055
01056
01057
01058 decoded = parse_get_nul_string(context);
01059 } else if (ret == WSP_FIELD_VALUE_ENCODED) {
01060 switch (field_type) {
01061 case WSP_HEADER_ACCEPT:
01062 case WSP_HEADER_CONTENT_TYPE:
01063 ch = wsp_content_type_to_cstr(val);
01064 if (!ch)
01065 warning(0, "Unknown content type 0x%02x.", val);
01066 break;
01067
01068 case WSP_HEADER_ACCEPT_CHARSET:
01069 ch = wsp_charset_to_cstr(val);
01070 if (!ch)
01071 warning(0, "Unknown charset 0x%02x.", val);
01072 break;
01073
01074 case WSP_HEADER_ACCEPT_ENCODING:
01075 case WSP_HEADER_CONTENT_ENCODING:
01076 ch = wsp_encoding_to_cstr(val);
01077 if (!ch)
01078 warning(0, "Unknown encoding 0x%02x.", val);
01079 break;
01080
01081 case WSP_HEADER_ACCEPT_LANGUAGE:
01082 case WSP_HEADER_CONTENT_LANGUAGE:
01083 ch = wsp_language_to_cstr(val);
01084 if (!ch)
01085 warning(0, "Unknown language 0x%02x.", val);
01086 break;
01087
01088 case WSP_HEADER_ACCEPT_RANGES:
01089 ch = wsp_ranges_to_cstr(val);
01090 if (!ch)
01091 warning(0, "Unknown ranges value 0x%02x.", val);
01092 break;
01093
01094 case WSP_HEADER_AGE:
01095 case WSP_HEADER_CONTENT_LENGTH:
01096 case WSP_HEADER_MAX_FORWARDS:
01097
01098 decoded = octstr_create("");
01099 octstr_append_decimal(decoded, val);
01100 break;
01101
01102 case WSP_HEADER_ALLOW:
01103 case WSP_HEADER_PUBLIC:
01104 ch = wsp_method_to_cstr(val);
01105 if (!ch) {
01106
01107 warning(0, "Unknown method 0x%02x.", val);
01108 }
01109 break;
01110
01111 case WSP_HEADER_CACHE_CONTROL:
01112 case WSP_HEADER_CACHE_CONTROL_V13:
01113 case WSP_HEADER_CACHE_CONTROL_V14:
01114 ch = wsp_cache_control_to_cstr(val);
01115 if (!ch)
01116 warning(0, "Unknown cache-control value 0x%02x.", val);
01117 break;
01118
01119 case WSP_HEADER_CONNECTION:
01120 ch = wsp_connection_to_cstr(val);
01121 if (!ch)
01122 warning(0, "Unknown connection value 0x%02x.", val);
01123 break;
01124
01125
01126 case WSP_HEADER_PRAGMA:
01127 if (val == 0)
01128 ch = (unsigned char *)"no-cache";
01129 else
01130 warning(0, "Unknown pragma value 0x%02x.", val);
01131 break;
01132
01133 case WSP_HEADER_TRANSFER_ENCODING:
01134 ch = wsp_transfer_encoding_to_cstr(val);
01135 if (!ch)
01136 warning(0, "Unknown transfer encoding value 0x%02x.", val);
01137 break;
01138
01139 case WSP_HEADER_VARY:
01140 ch = wsp_header_to_cstr(val);
01141 if (!ch)
01142 warning(0, "Unknown Vary field name 0x%02x.", val);
01143 break;
01144
01145 case WSP_HEADER_WARNING:
01146 decoded = octstr_create("");
01147 octstr_append_decimal(decoded, val);
01148 break;
01149
01150 case WSP_HEADER_BEARER_INDICATION:
01151 ch = wsp_bearer_indication_to_cstr(val);
01152 if (!ch)
01153 warning(0, "Unknown Bearer-Indication field name 0x%02x.", val);
01154 break;
01155
01156 case WSP_HEADER_ACCEPT_APPLICATION:
01157 ch = wsp_application_id_to_cstr(val);
01158 if (!ch)
01159 warning(0, "Unknown Accept-Application field name 0x%02x.", val);
01160 break;
01161
01162 default:
01163 if (headername) {
01164 warning(0, "Did not expect short-integer with "
01165 "'%s' header, skipping.", headername);
01166 }
01167 break;
01168 }
01169 } else if (ret == WSP_FIELD_VALUE_DATA) {
01170 switch (field_type) {
01171 case WSP_HEADER_ACCEPT:
01172 case WSP_HEADER_CONTENT_TYPE:
01173
01174
01175
01176 decoded = wsp_unpack_accept_general_form(context);
01177 break;
01178
01179 case WSP_HEADER_ACCEPT_CHARSET:
01180 decoded = wsp_unpack_accept_charset_general_form(context);
01181 break;
01182
01183 case WSP_HEADER_ACCEPT_LANGUAGE:
01184 decoded = unpack_accept_language_general_form(context);
01185 break;
01186
01187 case WSP_HEADER_AGE:
01188 case WSP_HEADER_CONTENT_LENGTH:
01189 case WSP_HEADER_MAX_FORWARDS:
01190 case WSP_HEADER_BEARER_INDICATION:
01191 case WSP_HEADER_ACCEPT_APPLICATION:
01192
01193 {
01194 long l = unpack_multi_octet_integer(context,
01195 parse_octets_left(context));
01196 decoded = octstr_create("");
01197 octstr_append_decimal(decoded, l);
01198 }
01199 break;
01200
01201 case WSP_HEADER_AUTHORIZATION:
01202 decoded = unpack_credentials(context);
01203 break;
01204
01205 case WSP_HEADER_PROXY_AUTHORIZATION:
01206 decoded = proxy_unpack_credentials(context);
01207 break;
01208
01209 case WSP_HEADER_CACHE_CONTROL:
01210 decoded = unpack_cache_directive(context);
01211 break;
01212
01213 case WSP_HEADER_CONTENT_MD5:
01214 decoded = parse_get_octets(context,
01215 parse_octets_left(context));
01216 octstr_binary_to_base64(decoded);
01217
01218 octstr_delete(decoded, octstr_len(decoded) - 2, 2);
01219 break;
01220
01221 case WSP_HEADER_CONTENT_RANGE:
01222 decoded = unpack_content_range(context);
01223 break;
01224
01225 case WSP_HEADER_DATE:
01226 case WSP_HEADER_EXPIRES:
01227 case WSP_HEADER_IF_MODIFIED_SINCE:
01228 case WSP_HEADER_IF_RANGE:
01229 case WSP_HEADER_IF_UNMODIFIED_SINCE:
01230 case WSP_HEADER_LAST_MODIFIED:
01231
01232 parse_skip(context, -1);
01233 decoded = wsp_unpack_date_value(context);
01234 break;
01235
01236 case WSP_HEADER_PRAGMA:
01237
01238
01239
01240 decoded = octstr_create("");
01241 if (unpack_parameter(context, decoded) < 0) {
01242 octstr_destroy(decoded);
01243 decoded = NULL;
01244 } else {
01245
01246 octstr_delete(decoded, 0, 2);
01247 }
01248 break;
01249
01250 case WSP_HEADER_PROXY_AUTHENTICATE:
01251 case WSP_HEADER_WWW_AUTHENTICATE:
01252 decoded = unpack_challenge(context);
01253 break;
01254
01255 case WSP_HEADER_RANGE:
01256 decoded = unpack_range_value(context);
01257 break;
01258
01259 case WSP_HEADER_RETRY_AFTER:
01260 decoded = unpack_retry_after(context);
01261 break;
01262
01263 case WSP_HEADER_WARNING:
01264 decoded = unpack_warning_value(context);
01265 break;
01266
01267 case WSP_HEADER_CONTENT_DISPOSITION:
01268 decoded = unpack_disposition(context);
01269 break;
01270
01271 case WSP_HEADER_ENCODING_VERSION:
01272 decoded = unpack_encoding_version(context);
01273 break;
01274
01275 default:
01276 if (headername) {
01277 warning(0, "Did not expect value-length with "
01278 "'%s' header, skipping.", headername);
01279 }
01280 break;
01281 }
01282 if (headername && parse_octets_left(context) > 0) {
01283 warning(0, "WSP: %s: skipping %ld trailing octets.",
01284 headername, parse_octets_left(context));
01285 }
01286 parse_skip_to_limit(context);
01287 parse_pop_limit(context);
01288 } else {
01289 panic(0, "Unknown field-value type %d.", ret);
01290 }
01291
01292 if (ch == NULL && decoded != NULL)
01293 ch = (unsigned char *)octstr_get_cstr(decoded);
01294 if (ch == NULL)
01295 goto value_error;
01296
01297 if (!headername) {
01298 warning(0, "Unknown header number 0x%02x.", field_type);
01299 goto value_error;
01300 }
01301
01302 http_header_add(unpacked, (char *)headername,(char *) ch);
01303 octstr_destroy(decoded);
01304 return;
01305
01306 value_error:
01307 warning(0, "Skipping faulty header.");
01308 octstr_destroy(decoded);
01309 }
01310
01311 void wsp_unpack_app_header(List *unpacked, ParseContext *context)
01312 {
01313 Octstr *header = NULL;
01314 Octstr *value = NULL;
01315
01316 header = parse_get_nul_string(context);
01317 value = parse_get_nul_string(context);
01318
01319 if (header && value) {
01320 http_header_add(unpacked, octstr_get_cstr(header),
01321 octstr_get_cstr(value));
01322 }
01323
01324 if (parse_error(context))
01325 warning(0, "Error parsing application-header.");
01326
01327 octstr_destroy(header);
01328 octstr_destroy(value);
01329 }
01330
01331 List *wsp_headers_unpack(Octstr *headers, int content_type_present)
01332 {
01333 ParseContext *context;
01334 int byte;
01335 List *unpacked;
01336 int code_page;
01337
01338 unpacked = http_create_empty_headers();
01339 context = parse_context_create(headers);
01340
01341 if (octstr_len(headers) > 0) {
01342 debug("wsp", 0, "WSP: decoding headers:");
01343 octstr_dump(headers, 0);
01344 }
01345
01346 if (content_type_present)
01347 wsp_unpack_well_known_field(unpacked,
01348 WSP_HEADER_CONTENT_TYPE, context);
01349
01350 code_page = 1;
01351
01352 while (parse_octets_left(context) > 0 && !parse_error(context)) {
01353 byte = parse_get_char(context);
01354
01355 if (byte == 127 || (byte >= 1 && byte <= 31)) {
01356 if (byte == 127)
01357 code_page = parse_get_char(context);
01358 else
01359 code_page = byte;
01360 if (code_page == 1)
01361 info(0, "Returning to code page 1 (default).");
01362 else {
01363 warning(0, "Shift to unknown code page %d.",
01364 code_page);
01365 warning(0, "Will try to skip headers until "
01366 "next known code page.");
01367 }
01368 } else if (byte >= 128) {
01369 if (code_page == 1)
01370 wsp_unpack_well_known_field(unpacked, byte - 128, context);
01371 else {
01372 debug("wsp", 0, "Skipping field 0x%02x.", byte);
01373 wsp_skip_field_value(context);
01374 }
01375 } else if (byte > 31 && byte < 127) {
01376
01377 parse_skip(context, -1);
01378 wsp_unpack_app_header(unpacked, context);
01379 } else {
01380 warning(0, "Unsupported token or header (start 0x%x)", byte);
01381 break;
01382 }
01383 }
01384
01385 if (gwlist_len(unpacked) > 0) {
01386 long i;
01387
01388 debug("wsp", 0, "WSP: decoded headers:");
01389 for (i = 0; i < gwlist_len(unpacked); i++) {
01390 Octstr *header = gwlist_get(unpacked, i);
01391 debug("wsp", 0, "%s", octstr_get_cstr(header));
01392 }
01393 debug("wsp", 0, "WSP: End of decoded headers.");
01394 }
01395
01396 parse_context_destroy(context);
01397 return unpacked;
01398 }
01399
01400
01401
01402
01403
01404
01405 static int pack_accept(Octstr *packet, Octstr *value);
01406 static int pack_accept_charset(Octstr *packet, Octstr *value);
01407 static int pack_accept_encoding(Octstr *packet, Octstr *value);
01408 static int pack_accept_language(Octstr *packet, Octstr *value);
01409 static int pack_cache_control(Octstr *packet, Octstr *value);
01410 static int pack_challenge(Octstr *packet, Octstr *value);
01411 static int pack_connection(Octstr *packet, Octstr *value);
01412 static int pack_content_disposition(Octstr *packet, Octstr *value);
01413 static int pack_content_range(Octstr *packet, Octstr *value);
01414 static int pack_credentials(Octstr *packet, Octstr *value);
01415 static int pack_encoding(Octstr *packet, Octstr *value);
01416 static int pack_expires(Octstr *packet, Octstr *value);
01417 static int pack_field_name(Octstr *packet, Octstr *value);
01418 static int pack_if_range(Octstr *packet, Octstr *value);
01419 static int pack_language(Octstr *packet, Octstr *value);
01420 static int pack_md5(Octstr *packet, Octstr *value);
01421 static int pack_method(Octstr *packet, Octstr *value);
01422 static int pack_pragma(Octstr *packet, Octstr *value);
01423 static int pack_range(Octstr *packet, Octstr *value);
01424 static int pack_range_unit(Octstr *packet, Octstr *value);
01425 static int pack_transfer_encoding(Octstr *packet, Octstr *value);
01426 static int pack_uri(Octstr *packet, Octstr *value);
01427 static int pack_warning(Octstr *packet, Octstr *value);
01428
01429
01430
01431
01432
01433 struct headerinfo headerinfo[] =
01434 {
01435 { WSP_HEADER_ACCEPT, pack_accept, LIST },
01436 { WSP_HEADER_ACCEPT_CHARSET, pack_accept_charset, LIST },
01437 { WSP_HEADER_ACCEPT_ENCODING, pack_accept_encoding, LIST },
01438 { WSP_HEADER_ACCEPT_LANGUAGE, pack_accept_language, LIST },
01439 { WSP_HEADER_ACCEPT_RANGES, pack_range_unit, LIST },
01440 { WSP_HEADER_AGE, wsp_pack_integer_string, 0 },
01441
01442
01443 { WSP_HEADER_ALLOW, pack_method, LIST },
01444 { WSP_HEADER_AUTHORIZATION, pack_credentials, BROKEN_LIST },
01445 { WSP_HEADER_CACHE_CONTROL, pack_cache_control, LIST },
01446 { WSP_HEADER_CACHE_CONTROL_V13, pack_cache_control, LIST },
01447 { WSP_HEADER_CACHE_CONTROL_V14, pack_cache_control, LIST },
01448 { WSP_HEADER_CONNECTION, pack_connection, LIST },
01449 { WSP_HEADER_CONTENT_BASE, pack_uri, 0 },
01450 { WSP_HEADER_CONTENT_ENCODING, pack_encoding, LIST },
01451 { WSP_HEADER_CONTENT_LANGUAGE, pack_language, LIST },
01452 { WSP_HEADER_CONTENT_LENGTH, wsp_pack_integer_string, 0 },
01453 { WSP_HEADER_CONTENT_LOCATION, pack_uri, 0 },
01454 { WSP_HEADER_CONTENT_MD5, pack_md5, 0 },
01455 { WSP_HEADER_CONTENT_RANGE, pack_content_range, 0 },
01456 { WSP_HEADER_CONTENT_TYPE, wsp_pack_content_type, 0 },
01457 { WSP_HEADER_DATE, wsp_pack_date, 0 },
01458 { WSP_HEADER_ETAG, wsp_pack_text, 0 },
01459 { WSP_HEADER_EXPIRES, pack_expires, 0 },
01460 { WSP_HEADER_FROM, wsp_pack_text, 0 },
01461 { WSP_HEADER_HOST, wsp_pack_text, 0 },
01462 { WSP_HEADER_IF_MODIFIED_SINCE, wsp_pack_date, 0 },
01463 { WSP_HEADER_IF_MATCH, wsp_pack_text, 0 },
01464 { WSP_HEADER_IF_NONE_MATCH, wsp_pack_text, 0 },
01465 { WSP_HEADER_IF_RANGE, pack_if_range, 0 },
01466 { WSP_HEADER_IF_UNMODIFIED_SINCE, wsp_pack_date, 0 },
01467 { WSP_HEADER_LAST_MODIFIED, wsp_pack_date, 0 },
01468 { WSP_HEADER_LOCATION, pack_uri, 0 },
01469 { WSP_HEADER_MAX_FORWARDS, wsp_pack_integer_string, 0 },
01470 { WSP_HEADER_PRAGMA, pack_pragma, LIST },
01471 { WSP_HEADER_PROXY_AUTHENTICATE, pack_challenge, BROKEN_LIST },
01472 { WSP_HEADER_PROXY_AUTHORIZATION, pack_credentials, BROKEN_LIST },
01473 { WSP_HEADER_PUBLIC, pack_method, LIST },
01474 { WSP_HEADER_RANGE, pack_range, 0 },
01475 { WSP_HEADER_REFERER, pack_uri, 0 },
01476 { WSP_HEADER_RETRY_AFTER, wsp_pack_retry_after, 0 },
01477 { WSP_HEADER_SERVER, wsp_pack_text, 0 },
01478 { WSP_HEADER_TRANSFER_ENCODING, pack_transfer_encoding, LIST },
01479 { WSP_HEADER_UPGRADE, wsp_pack_text, LIST },
01480 { WSP_HEADER_USER_AGENT, wsp_pack_text, 0 },
01481 { WSP_HEADER_VARY, pack_field_name, LIST },
01482 { WSP_HEADER_VIA, wsp_pack_text, LIST },
01483 { WSP_HEADER_WARNING, pack_warning, LIST },
01484 { WSP_HEADER_WWW_AUTHENTICATE, pack_challenge, BROKEN_LIST },
01485 { WSP_HEADER_CONTENT_DISPOSITION, pack_content_disposition, 0 },
01486 { WSP_HEADER_PUSH_FLAG, wsp_pack_integer_string, 0},
01487 { WSP_HEADER_X_WAP_CONTENT_URI, pack_uri, 0},
01488 { WSP_HEADER_X_WAP_INITIATOR_URI, pack_uri, 0},
01489 { WSP_HEADER_X_WAP_APPLICATION_ID, wsp_pack_integer_string, 0},
01490 { WSP_HEADER_CONTENT_ID, wsp_pack_quoted_text, 0},
01491 { WSP_HEADER_ENCODING_VERSION, wsp_pack_version_value, 0 }
01492
01493 };
01494
01495 static Parameter *parm_create(Octstr *key, Octstr *value)
01496 {
01497 Parameter *parm;
01498
01499 parm = gw_malloc(sizeof(*parm));
01500 parm->key = key;
01501 parm->value = value;
01502 return parm;
01503 }
01504
01505 static void parm_destroy(Parameter *parm)
01506 {
01507 if (parm == NULL)
01508 return;
01509
01510 octstr_destroy(parm->key);
01511 octstr_destroy(parm->value);
01512 gw_free(parm);
01513 }
01514
01515 void parm_destroy_item(void *parm)
01516 {
01517 parm_destroy(parm);
01518 }
01519
01520 static Parameter *parm_parse(Octstr *value)
01521 {
01522 long pos;
01523 Octstr *key, *val;
01524
01525 pos = octstr_search_char(value, '=', 0);
01526 if (pos > 0) {
01527 key = octstr_copy(value, 0, pos);
01528 val = octstr_copy(value, pos + 1, octstr_len(value) - pos);
01529 octstr_strip_blanks(key);
01530 octstr_strip_blanks(val);
01531 } else {
01532 key = octstr_duplicate(value);
01533 val = NULL;
01534 }
01535
01536 return parm_create(key, val);
01537 }
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553 List *wsp_strip_parameters(Octstr *value)
01554 {
01555 long pos;
01556 long len;
01557 int c;
01558 long end;
01559 List *parms;
01560 long firstparm;
01561
01562 len = octstr_len(value);
01563
01564 for (pos = 0; pos < len; pos++) {
01565 c = octstr_get_char(value, pos);
01566 if (c == ';')
01567 break;
01568 else if (c == '"')
01569 pos += http_header_quoted_string_len(value, pos) - 1;
01570 }
01571
01572 if (pos >= len)
01573 return NULL;
01574
01575 parms = gwlist_create();
01576 firstparm = pos;
01577
01578 for (pos++; pos > 0 && pos < len; pos++) {
01579 Octstr *key = NULL;
01580 Octstr *val = NULL;
01581
01582 end = octstr_search_char(value, '=', pos);
01583 if (end < 0)
01584 end = octstr_search_char(value, ';', pos);
01585 if (end < 0)
01586 end = octstr_len(value);
01587 key = octstr_copy(value, pos, end - pos);
01588 octstr_strip_blanks(key);
01589 pos = end;
01590
01591 if (octstr_get_char(value, pos) == '=') {
01592 pos++;
01593 while (isspace(octstr_get_char(value, pos)))
01594 pos++;
01595 if (octstr_get_char(value, pos) == '"')
01596 end = pos + http_header_quoted_string_len(value, pos);
01597 else
01598 end = octstr_search_char(value, ';', pos);
01599 if (end < 0)
01600 end = octstr_len(value);
01601 val = octstr_copy(value, pos, end - pos);
01602 octstr_strip_blanks(val);
01603 pos = end;
01604 pos = octstr_search_char(value, ';', pos);
01605 }
01606
01607 gwlist_append(parms, parm_create(key, val));
01608 }
01609
01610 octstr_delete(value, firstparm, octstr_len(value) - firstparm);
01611 octstr_strip_blanks(value);
01612 return parms;
01613 }
01614
01615 int wsp_pack_text(Octstr *packed, Octstr *text)
01616 {
01617
01618
01619 if (octstr_get_char(text, 0) >= 128 || octstr_get_char(text, 0) < 32)
01620 octstr_append_char(packed, WSP_QUOTE);
01621 octstr_append(packed, text);
01622 octstr_append_char(packed, 0);
01623 return 0;
01624 }
01625
01626
01627 int wsp_pack_quoted_text(Octstr *packed, Octstr *text)
01628 {
01629 octstr_append_char(packed, '"');
01630 octstr_append(packed,text);
01631 octstr_append_char(packed,0);
01632 return 0;
01633 }
01634
01635
01636
01637 static void pack_quoted_string(Octstr *packed, Octstr *text)
01638 {
01639 octstr_append(packed, text);
01640 if (octstr_get_char(text, octstr_len(text) - 1) == '"' &&
01641 octstr_get_char(text, 0) == '"')
01642 octstr_delete(packed, octstr_len(packed) - 1, 1);
01643 octstr_append_char(packed, 0);
01644 }
01645
01646
01647 static int is_separator_char(int c)
01648 {
01649 switch (c) {
01650 case '(':
01651 case ')':
01652 case '<':
01653 case '>':
01654 case '@':
01655 case ',':
01656 case ';':
01657 case ':':
01658 case '\\':
01659 case '"':
01660 case '/':
01661 case '[':
01662 case ']':
01663 case '?':
01664 case '=':
01665 case '{':
01666 case '}':
01667 case 32:
01668 case 9:
01669 return 1;
01670 default:
01671 return 0;
01672 }
01673 }
01674
01675
01676 static int is_token_char(int c)
01677 {
01678 return c >= 32 && c < 127 && !is_separator_char(c);
01679 }
01680
01681
01682 static int is_token(Octstr *token)
01683 {
01684 return octstr_len(token) > 0 &&
01685 octstr_check_range(token, 0, octstr_len(token), is_token_char);
01686 }
01687
01688
01689
01690 static int parse_qvalue(Octstr *value)
01691 {
01692 int qvalue;
01693
01694 if (value == NULL)
01695 return -1;
01696
01697 if (!isdigit(octstr_get_char(value, 0)))
01698 return -1;
01699
01700 qvalue = (octstr_get_char(value, 0) - '0') * 1000;
01701
01702 if (octstr_get_char(value, 1) != '.')
01703 goto gotvalue;
01704
01705 if (!isdigit(octstr_get_char(value, 2)))
01706 goto gotvalue;
01707 qvalue += (octstr_get_char(value, 2) - '0') * 100;
01708
01709
01710 if (!isdigit(octstr_get_char(value, 3)))
01711 goto gotvalue;
01712 qvalue += (octstr_get_char(value, 3) - '0') * 10;
01713
01714 if (!isdigit(octstr_get_char(value, 4)))
01715 goto gotvalue;
01716 qvalue += (octstr_get_char(value, 4) - '0');
01717
01718 gotvalue:
01719 if (qvalue < 0 || qvalue > 1000)
01720 return -1;
01721
01722 return qvalue;
01723 }
01724
01725 static int get_qvalue(List *parms, int default_qvalue)
01726 {
01727 long i;
01728 Parameter *parm;
01729 int qvalue;
01730
01731 for (i = 0; i < gwlist_len(parms); i++) {
01732 parm = gwlist_get(parms, i);
01733 if (octstr_str_compare(parm->key, "q") == 0 ||
01734 octstr_str_compare(parm->key, "Q") == 0) {
01735 qvalue = parse_qvalue(parm->value);
01736 if (qvalue >= 0)
01737 return qvalue;
01738 }
01739 }
01740
01741 return default_qvalue;
01742 }
01743
01744 static int pack_qvalue(Octstr *packed, int qvalue)
01745 {
01746
01747
01748 if (qvalue == 1000)
01749 return -1;
01750
01751
01752 if (qvalue % 10 == 0)
01753 qvalue = qvalue / 10 + 1;
01754 else
01755 qvalue = qvalue + 100;
01756 octstr_append_uintvar(packed, qvalue);
01757 return 0;
01758 }
01759
01760
01761 void wsp_pack_value(Octstr *packed, Octstr *encoded)
01762 {
01763 long len;
01764
01765 len = octstr_len(encoded);
01766 if (len <= 30)
01767 octstr_append_char(packed, len);
01768 else {
01769 octstr_append_char(packed, 31);
01770 octstr_append_uintvar(packed, len);
01771 }
01772
01773 octstr_append(packed, encoded);
01774 }
01775
01776 void wsp_pack_long_integer(Octstr *packed, unsigned long integer)
01777 {
01778 long oldlen = octstr_len(packed);
01779 unsigned char octet;
01780 long len;
01781
01782 if (integer == 0) {
01783
01784 octstr_append_char(packed, 1);
01785 octstr_append_char(packed, 0);
01786 return;
01787 }
01788
01789
01790
01791 for (len = 0; integer != 0; integer >>= 8, len++) {
01792 octet = integer & 0xff;
01793 octstr_insert_data(packed, oldlen, (char *)&octet, 1);
01794 }
01795
01796 octet = len;
01797 octstr_insert_data(packed, oldlen, (char *)&octet, 1);
01798 }
01799
01800 void wsp_pack_short_integer(Octstr *packed, unsigned long integer)
01801 {
01802 gw_assert(integer <= MAX_SHORT_INTEGER);
01803
01804 octstr_append_char(packed, integer + 0x80);
01805 }
01806
01807 void wsp_pack_integer_value(Octstr *packed, unsigned long integer)
01808 {
01809 if (integer <= MAX_SHORT_INTEGER)
01810 wsp_pack_short_integer(packed, integer);
01811 else
01812 wsp_pack_long_integer(packed, integer);
01813 }
01814
01815 int wsp_pack_integer_string(Octstr *packed, Octstr *value)
01816 {
01817 unsigned long integer;
01818 long pos;
01819 int c;
01820 int digit;
01821
01822 integer = 0;
01823 for (pos = 0; pos < octstr_len(value); pos++) {
01824 c = octstr_get_char(value, pos);
01825 if (!isdigit(c))
01826 break;
01827 digit = c - '0';
01828 if (integer > ULONG_MAX / 10)
01829 goto overflow;
01830 integer *= 10;
01831 if (integer > ULONG_MAX - digit)
01832 goto overflow;
01833 integer += digit;
01834 }
01835
01836 wsp_pack_integer_value(packed, integer);
01837 return 0;
01838
01839 overflow:
01840 warning(0, "WSP: Number too large to handle: '%s'.",
01841 octstr_get_cstr(value));
01842 return -1;
01843 }
01844
01845
01846 int wsp_pack_version_value(Octstr *packed, Octstr *version)
01847 {
01848 long major, minor;
01849 long pos;
01850
01851 pos = octstr_parse_long(&major, version, 0, 10);
01852 if (pos < 0 || major < 1 || major > 7)
01853 goto usetext;
01854
01855 if (pos == octstr_len(version))
01856 minor = 15;
01857 else {
01858 if (octstr_get_char(version, pos) != '.')
01859 goto usetext;
01860 pos = octstr_parse_long(&minor, version, pos + 1, 10);
01861 if (pos != octstr_len(version) || minor < 0 || minor > 14)
01862 goto usetext;
01863 }
01864
01865 wsp_pack_short_integer(packed, major << 4 | minor);
01866 return 0;
01867
01868 usetext:
01869 wsp_pack_text(packed, version);
01870 return 0;
01871 }
01872
01873 int wsp_pack_constrained_value(Octstr *packed, Octstr *text, long value)
01874 {
01875 if (value >= 0)
01876 wsp_pack_short_integer(packed, value);
01877 else
01878 wsp_pack_text(packed, text);
01879 return 0;
01880 }
01881
01882 static void pack_parameter(Octstr *packed, Parameter *parm)
01883 {
01884 long keytoken;
01885 long tmp;
01886 long start;
01887
01888 start = octstr_len(packed);
01889
01890
01891
01892
01893 keytoken = wsp_string_to_versioned_parameter(parm->key, WSP_1_2);
01894
01895 if (keytoken >= 0) {
01896
01897
01898 wsp_pack_integer_value(packed, keytoken);
01899
01900
01901
01902 if (parm->value == NULL) {
01903 octstr_append_char(packed, 0);
01904 return;
01905 } else switch (keytoken) {
01906 case 0:
01907 tmp = parse_qvalue(parm->value);
01908 if (tmp >= 0) {
01909 if (pack_qvalue(packed, tmp) < 0)
01910 octstr_delete(packed, start,
01911 octstr_len(packed) - start);
01912 return;
01913 }
01914 break;
01915 case 1:
01916 tmp = wsp_string_to_charset(parm->value);
01917 if (tmp >= 0) {
01918 wsp_pack_integer_value(packed, tmp);
01919 return;
01920 }
01921 break;
01922 case 2:
01923 wsp_pack_version_value(packed, parm->value);
01924 return;
01925 case 3:
01926 if (octstr_check_range(parm->value, 0,
01927 octstr_len(parm->value),
01928 gw_isdigit) &&
01929 wsp_pack_integer_string(packed, parm->value) >= 0)
01930 return;
01931 break;
01932 case 5:
01933 case 6:
01934 break;
01935 case 7:
01936 if (pack_field_name(packed, parm->value) >= 0)
01937 return;
01938 break;
01939 case 8:
01940 if (octstr_parse_long(&tmp, parm->value, 0, 10)
01941 == octstr_len(parm->value) &&
01942 tmp >= 0 && tmp <= MAX_SHORT_INTEGER) {
01943 wsp_pack_short_integer(packed, tmp);
01944 return;
01945 }
01946 break;
01947 }
01948 pack_quoted_string(packed, parm->value);
01949 } else {
01950
01951 wsp_pack_text(packed, parm->key);
01952
01953 if (parm->value == NULL) {
01954 octstr_append_char(packed, 0);
01955 return;
01956 }
01957
01958 if (octstr_parse_long(&tmp, parm->value, 0, 10)
01959 == octstr_len(parm->value)) {
01960 wsp_pack_integer_value(packed, tmp);
01961 } else {
01962 pack_quoted_string(packed, parm->value);
01963 }
01964 }
01965 }
01966
01967 void wsp_pack_parameters(Octstr *packed, List *parms)
01968 {
01969 long i;
01970 Parameter *parm;
01971
01972 for (i = 0; i < gwlist_len(parms); i++) {
01973 parm = gwlist_get(parms, i);
01974 pack_parameter(packed, parm);
01975 }
01976 }
01977
01978 static int pack_uri(Octstr *packed, Octstr *value)
01979 {
01980 wsp_pack_text(packed, value);
01981 return 0;
01982 }
01983
01984 static int pack_md5(Octstr *packed, Octstr *value)
01985 {
01986 Octstr *binary;
01987
01988 binary = octstr_duplicate(value);
01989 octstr_base64_to_binary(binary);
01990
01991 if (octstr_len(binary) != 16) {
01992 error(0, "WSP: MD5 value not 128 bits.");
01993 return -1;
01994 }
01995
01996 octstr_append_char(packed, 16);
01997 octstr_append(packed, binary);
01998
01999 octstr_destroy(binary);
02000
02001 return 0;
02002 }
02003
02004
02005
02006
02007
02008 static int pack_challenge(Octstr *packed, Octstr *value)
02009 {
02010 Octstr *encoding = NULL;
02011 Octstr *scheme = NULL;
02012 Octstr *basic = octstr_imm("Basic");
02013 Octstr *realm = octstr_imm("realm");
02014 Octstr *parmstring = NULL;
02015 List *parms = NULL;
02016 Parameter *realmparm = NULL;
02017 long realmpos = -1;
02018 Octstr *realmval = NULL;
02019 long pos;
02020
02021 encoding = octstr_create("");
02022
02023
02024 for (pos = 0; pos < octstr_len(value); pos++) {
02025 if (!is_token_char(octstr_get_char(value, pos)))
02026 break;
02027 }
02028 scheme = octstr_copy(value, 0, pos);
02029 octstr_strip_blanks(scheme);
02030
02031
02032 while (isspace(octstr_get_char(value, pos)))
02033 pos++;
02034
02035 if (octstr_case_compare(scheme, basic) == 0) {
02036 parmstring = octstr_copy(value, pos, octstr_len(value) - pos);
02037 realmparm = parm_parse(parmstring);
02038
02039 octstr_append_char(encoding, BASIC_AUTHENTICATION);
02040 realmpos = octstr_len(encoding);
02041 } else {
02042 long i;
02043
02044 wsp_pack_text(encoding, scheme);
02045 realmpos = octstr_len(encoding);
02046
02047
02048 parms = wsp_strip_parameters(value);
02049 for (i = 0; i < gwlist_len(parms); i++) {
02050 Parameter *parm = gwlist_get(parms, i);
02051 if (octstr_case_compare(realm, parm->key) == 0) {
02052 realmparm = parm;
02053 gwlist_delete(parms, i, 1);
02054 break;
02055 }
02056 }
02057
02058 wsp_pack_parameters(encoding, parms);
02059 }
02060
02061
02062
02063
02064
02065
02066
02067
02068
02069 if (realmparm == NULL ||
02070 octstr_case_compare(realmparm->key, realm) != 0 ||
02071 realmparm->value == NULL)
02072 goto error;
02073
02074
02075 if (octstr_get_char(realmparm->value, 0) == '"' &&
02076 octstr_get_char(realmparm->value, octstr_len(realmparm->value) - 1) == '"') {
02077 octstr_delete(realmparm->value, 0, 1);
02078 octstr_delete(realmparm->value, octstr_len(realmparm->value) - 1, 1);
02079 }
02080
02081 gw_assert(realmpos >= 0);
02082
02083 realmval = octstr_create("");
02084 wsp_pack_text(realmval, realmparm->value);
02085 octstr_insert(encoding, realmval, realmpos);
02086
02087 wsp_pack_value(packed, encoding);
02088
02089 octstr_destroy(encoding);
02090 octstr_destroy(scheme);
02091 octstr_destroy(parmstring);
02092 parm_destroy(realmparm);
02093 gwlist_destroy(parms, parm_destroy_item);
02094 octstr_destroy(realmval);
02095 return 0;
02096
02097 error:
02098 warning(0, "WSP: Cannot parse challenge.");
02099 octstr_destroy(encoding);
02100 octstr_destroy(scheme);
02101 octstr_destroy(parmstring);
02102 parm_destroy(realmparm);
02103 gwlist_destroy(parms, parm_destroy_item);
02104 octstr_destroy(realmval);
02105 return -1;
02106 }
02107
02108
02109
02110
02111
02112 static int pack_credentials(Octstr *packed, Octstr *value)
02113 {
02114 Octstr *encoding = NULL;
02115 Octstr *scheme = NULL;
02116 Octstr *basic = NULL;
02117 long pos;
02118
02119 encoding = octstr_create("");
02120
02121
02122 for (pos = 0; pos < octstr_len(value); pos++) {
02123 if (!is_token_char(octstr_get_char(value, pos)))
02124 break;
02125 }
02126 scheme = octstr_copy(value, 0, pos);
02127 octstr_strip_blanks(scheme);
02128
02129
02130 while (isspace(octstr_get_char(value, pos)))
02131 pos++;
02132
02133 basic = octstr_imm("Basic");
02134 if (octstr_case_compare(scheme, basic) == 0) {
02135 Octstr *cookie;
02136 Octstr *userid;
02137 Octstr *password;
02138
02139 octstr_append_char(encoding, BASIC_AUTHENTICATION);
02140
02141 cookie = octstr_copy(value, pos, octstr_len(value) - pos);
02142 octstr_base64_to_binary(cookie);
02143 pos = octstr_search_char(cookie, ':', 0);
02144 if (pos < 0) {
02145 warning(0, "WSP: bad cookie in credentials '%s'.",
02146 octstr_get_cstr(value));
02147 octstr_destroy(cookie);
02148 goto error;
02149 }
02150
02151 userid = octstr_copy(cookie, 0, pos);
02152 password = octstr_copy(cookie, pos + 1, octstr_len(cookie) - pos);
02153 wsp_pack_text(encoding, userid);
02154 wsp_pack_text(encoding, password);
02155
02156 octstr_destroy(cookie);
02157 octstr_destroy(userid);
02158 octstr_destroy(password);
02159 } else {
02160 List *parms;
02161
02162 wsp_pack_text(encoding, scheme);
02163 parms = wsp_strip_parameters(value);
02164 wsp_pack_parameters(encoding, parms);
02165 gwlist_destroy(parms, parm_destroy_item);
02166 }
02167
02168 wsp_pack_value(packed, encoding);
02169 octstr_destroy(encoding);
02170 octstr_destroy(scheme);
02171
02172 return 0;
02173
02174 error:
02175 octstr_destroy(encoding);
02176 octstr_destroy(scheme);
02177 return -1;
02178 }
02179
02180 int wsp_pack_date(Octstr *packed, Octstr *value)
02181 {
02182 long timeval;
02183
02184
02185
02186
02187 timeval = date_parse_http(value);
02188 if (timeval == -1) {
02189 warning(0, "WSP headers: cannot decode date '%s'",
02190 octstr_get_cstr(value));
02191 return -1;
02192 }
02193
02194
02195 wsp_pack_long_integer(packed, (unsigned long) timeval);
02196 return 0;
02197 }
02198
02199 static int pack_connection(Octstr *packed, Octstr *value)
02200 {
02201 return wsp_pack_constrained_value(packed, value,
02202 wsp_string_to_connection(value));
02203 }
02204
02205 static int pack_encoding(Octstr *packed, Octstr *value)
02206 {
02207 return wsp_pack_constrained_value(packed, value,
02208 wsp_string_to_encoding(value));
02209 }
02210
02211 static int pack_field_name(Octstr *packed, Octstr *value)
02212 {
02213
02214
02215
02216 return wsp_pack_constrained_value(packed, value,
02217 wsp_string_to_versioned_header(value, WSP_1_2));
02218 }
02219
02220 static int pack_language(Octstr *packed, Octstr *value)
02221 {
02222 long language;
02223
02224
02225
02226 language = wsp_string_to_language(value);
02227 if (language >= 0)
02228 wsp_pack_integer_value(packed, language);
02229 else
02230 wsp_pack_text(packed, value);
02231 return 0;
02232 }
02233
02234
02235 static int pack_method(Octstr *packed, Octstr *value)
02236 {
02237
02238
02239 return wsp_pack_constrained_value(packed, value,
02240 wsp_string_to_method(value));
02241 }
02242
02243
02244 static int pack_range_unit(Octstr *packed, Octstr *value)
02245 {
02246 return wsp_pack_constrained_value(packed, value,
02247 wsp_string_to_ranges(value));
02248 }
02249
02250
02251
02252 static int pack_range_value(Octstr *packed, Octstr *value, long pos)
02253 {
02254 long first_byte_pos;
02255 long last_byte_pos;
02256 long suffix_length;
02257 Octstr *encoding;
02258
02259 while (isspace(octstr_get_char(value, pos)))
02260 pos++;
02261
02262 if (isdigit(octstr_get_char(value, pos))) {
02263
02264 pos = octstr_parse_long(&first_byte_pos, value, pos, 10);
02265 if (pos < 0 || first_byte_pos < 0)
02266 return -1;
02267
02268 while (isspace(octstr_get_char(value, pos)))
02269 pos++;
02270
02271 if (octstr_get_char(value, pos) != '-')
02272 return -1;
02273 pos++;
02274
02275 while (isspace(octstr_get_char(value, pos)))
02276 pos++;
02277
02278 if (isdigit(octstr_get_char(value, pos))) {
02279 pos = octstr_parse_long(&last_byte_pos, value, pos, 10);
02280 if (pos < 0 || last_byte_pos < 0)
02281 return -1;
02282 } else {
02283 last_byte_pos = -1;
02284 }
02285
02286 encoding = octstr_create("");
02287 octstr_append_char(encoding, BYTE_RANGE);
02288 octstr_append_uintvar(encoding, first_byte_pos);
02289 if (last_byte_pos >= 0)
02290 octstr_append_uintvar(encoding, last_byte_pos);
02291 wsp_pack_value(packed, encoding);
02292 octstr_destroy(encoding);
02293 } else if (octstr_get_char(value, pos) == '-') {
02294
02295 pos++;
02296
02297 pos = octstr_parse_long(&suffix_length, value, pos, 10);
02298 if (pos < 0 || suffix_length < 0)
02299 return -1;
02300
02301 encoding = octstr_create("");
02302 octstr_append_char(encoding, SUFFIX_BYTE_RANGE);
02303 octstr_append_uintvar(encoding, suffix_length);
02304 wsp_pack_value(packed, encoding);
02305 octstr_destroy(encoding);
02306 } else
02307 return -1;
02308
02309 return pos;
02310 }
02311
02312 static int pack_transfer_encoding(Octstr *packed, Octstr *value)
02313 {
02314 return wsp_pack_constrained_value(packed, value,
02315 wsp_string_to_transfer_encoding(value));
02316 }
02317
02318
02319 static int pack_accept(Octstr *packed, Octstr *value)
02320 {
02321 List *parms;
02322 long media;
02323
02324 parms = wsp_strip_parameters(value);
02325
02326
02327 media = wsp_string_to_versioned_content_type(value, WSP_1_2);
02328
02329
02330 if (parms == NULL && media <= MAX_SHORT_INTEGER) {
02331 wsp_pack_constrained_value(packed, value, media);
02332 } else {
02333 Octstr *encoding = octstr_create("");
02334
02335 if (media >= 0)
02336 wsp_pack_integer_value(encoding, media);
02337 else
02338 wsp_pack_text(encoding, value);
02339
02340 wsp_pack_parameters(encoding, parms);
02341 wsp_pack_value(packed, encoding);
02342 octstr_destroy(encoding);
02343 }
02344
02345 gwlist_destroy(parms, parm_destroy_item);
02346 return 0;
02347 }
02348
02349 static int pack_accept_charset(Octstr *packed, Octstr *value)
02350 {
02351 List *parms;
02352 long charset;
02353 long qvalue;
02354
02355 parms = wsp_strip_parameters(value);
02356 charset = wsp_string_to_charset(value);
02357 qvalue = 1000;
02358 if (parms)
02359 qvalue = get_qvalue(parms, qvalue);
02360 gwlist_destroy(parms, parm_destroy_item);
02361
02362
02363 if (qvalue == 1000 && charset <= MAX_SHORT_INTEGER) {
02364 wsp_pack_constrained_value(packed, value, charset);
02365 } else {
02366 Octstr *encoding = octstr_create("");
02367
02368 if (charset >= 0)
02369 wsp_pack_integer_value(encoding, charset);
02370 else
02371 wsp_pack_text(encoding, value);
02372
02373 if (qvalue != 1000)
02374 pack_qvalue(encoding, qvalue);
02375 wsp_pack_value(packed, encoding);
02376 octstr_destroy(encoding);
02377 }
02378
02379 return 0;
02380 }
02381
02382
02383
02384
02385
02386
02387 static int pack_accept_encoding(Octstr *packed, Octstr *value)
02388 {
02389 List *parms;
02390 int qvalue;
02391
02392 qvalue = 1000;
02393
02394 parms = wsp_strip_parameters(value);
02395 if (parms)
02396 qvalue = get_qvalue(parms, qvalue);
02397 gwlist_destroy(parms, parm_destroy_item);
02398
02399 if (qvalue > 0) {
02400 if (qvalue < 1000)
02401 warning(0, "Cannot encode q-value in Accept-Encoding.");
02402 pack_encoding(packed, value);
02403 } else {
02404 warning(0, "Cannot encode q=0 in Accept-Encoding; skipping this encoding.");
02405 return -1;
02406 }
02407
02408 return 0;
02409 }
02410
02411 static int pack_accept_language(Octstr *packed, Octstr *value)
02412 {
02413 List *parms;
02414 long language;
02415 long qvalue;
02416
02417 parms = wsp_strip_parameters(value);
02418 language = wsp_string_to_language(value);
02419 qvalue = 1000;
02420 if (parms)
02421 qvalue = get_qvalue(parms, qvalue);
02422 gwlist_destroy(parms, parm_destroy_item);
02423
02424
02425
02426 if (qvalue == 1000 && language <= MAX_SHORT_INTEGER) {
02427 wsp_pack_constrained_value(packed, value, language);
02428 } else {
02429 Octstr *encoding = octstr_create("");
02430
02431 if (language >= 0)
02432 wsp_pack_integer_value(encoding, language);
02433 else
02434 wsp_pack_text(encoding, value);
02435
02436 if (qvalue != 1000)
02437 pack_qvalue(encoding, qvalue);
02438 wsp_pack_value(packed, encoding);
02439 octstr_destroy(encoding);
02440 }
02441
02442 return 0;
02443 }
02444
02445 static int pack_cache_control(Octstr *packed, Octstr *value)
02446 {
02447 Parameter *parm;
02448 long tmp;
02449
02450 parm = parm_parse(value);
02451
02452 if (parm->value == NULL) {
02453 wsp_pack_constrained_value(packed, value,
02454 wsp_string_to_cache_control(parm->key));
02455 } else {
02456 Octstr *encoding = octstr_create("");
02457
02458 tmp = wsp_string_to_cache_control(parm->key);
02459 if (tmp < 0) {
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469 wsp_pack_text(encoding, octstr_imm(""));
02470 pack_parameter(encoding, parm);
02471 } else {
02472 int done = 0;
02473 Octstr *value_encoding;
02474 List *names;
02475 Octstr *element;
02476
02477 value_encoding = octstr_create("");
02478 switch (tmp) {
02479 case WSP_CACHE_CONTROL_NO_CACHE:
02480 case WSP_CACHE_CONTROL_PRIVATE:
02481 if (octstr_get_char(parm->value, 0) == '"')
02482 octstr_delete(parm->value, 0, 1);
02483 if (octstr_get_char(parm->value, octstr_len(parm->value) - 1) == '"')
02484 octstr_delete(parm->value, octstr_len(parm->value) - 1, 1);
02485 names = http_header_split_value(parm->value);
02486 while ((element = gwlist_consume(names))) {
02487 pack_field_name(value_encoding, element);
02488 octstr_destroy(element);
02489 }
02490 gwlist_destroy(names, octstr_destroy_item);
02491 done = 1;
02492 break;
02493
02494 case WSP_CACHE_CONTROL_MAX_AGE:
02495 case WSP_CACHE_CONTROL_MAX_STALE:
02496 case WSP_CACHE_CONTROL_MIN_FRESH:
02497 if (wsp_pack_integer_string(value_encoding, parm->value) >= 0)
02498 done = 1;
02499 break;
02500 }
02501
02502 if (done) {
02503 wsp_pack_short_integer(encoding, tmp);
02504 octstr_append(encoding, value_encoding);
02505 } else {
02506
02507 pack_parameter(encoding, parm);
02508 }
02509 octstr_destroy(value_encoding);
02510 }
02511
02512 wsp_pack_value(packed, encoding);
02513 octstr_destroy(encoding);
02514 }
02515
02516 parm_destroy(parm);
02517 return 1;
02518 }
02519
02520 static int pack_content_disposition(Octstr *packed, Octstr *value)
02521 {
02522 List *parms;
02523 long disposition;
02524
02525 parms = wsp_strip_parameters(value);
02526 disposition = wsp_string_to_disposition(value);
02527
02528 if (disposition >= 0) {
02529 Octstr *encoding = octstr_create("");
02530
02531 wsp_pack_short_integer(encoding, disposition);
02532 wsp_pack_parameters(encoding, parms);
02533 wsp_pack_value(packed, encoding);
02534 octstr_destroy(encoding);
02535 } else {
02536 warning(0, "WSP: Cannot encode Content-Disposition '%s'.",
02537 octstr_get_cstr(value));
02538 goto error;
02539 }
02540
02541 gwlist_destroy(parms, parm_destroy_item);
02542 return 0;
02543
02544 error:
02545 gwlist_destroy(parms, parm_destroy_item);
02546 return -1;
02547 }
02548
02549 static int pack_content_range(Octstr *packed, Octstr *value)
02550 {
02551 Octstr *bytes;
02552 long pos;
02553 long firstbyte, lastbyte, instancelen;
02554 Octstr *encoding;
02555
02556 bytes = octstr_imm("bytes ");
02557 if (octstr_ncompare(value, bytes, octstr_len(bytes)) != 0)
02558 goto error;
02559
02560 pos = octstr_len(bytes);
02561 while (isspace(octstr_get_char(value, pos)))
02562 pos++;
02563 if (octstr_get_char(value, pos) == '*')
02564 goto warning;
02565 pos = octstr_parse_long(&firstbyte, value, pos, 10);
02566 if (pos < 0)
02567 goto error;
02568
02569 while (isspace(octstr_get_char(value, pos)))
02570 pos++;
02571 if (octstr_get_char(value, pos++) != '-')
02572 goto error;
02573
02574 pos = octstr_parse_long(&lastbyte, value, pos, 10);
02575 if (pos < 0)
02576 goto error;
02577
02578 while (isspace(octstr_get_char(value, pos)))
02579 pos++;
02580 if (octstr_get_char(value, pos++) != '/')
02581 goto error;
02582
02583 while (isspace(octstr_get_char(value, pos)))
02584 pos++;
02585 if (octstr_get_char(value, pos) == '*')
02586 goto warning;
02587 pos = octstr_parse_long(&instancelen, value, pos, 10);
02588 if (pos < 0)
02589 goto error;
02590
02591
02592
02593
02594
02595 if (lastbyte < firstbyte || instancelen < lastbyte) {
02596 warning(0, "WSP: Content-Range '%s' is invalid.",
02597 octstr_get_cstr(value));
02598 return -1;
02599 }
02600
02601 encoding = octstr_create("");
02602 octstr_append_uintvar(encoding, firstbyte);
02603 octstr_append_uintvar(encoding, instancelen);
02604 wsp_pack_value(packed, encoding);
02605 octstr_destroy(encoding);
02606
02607 return 0;
02608
02609 error:
02610 warning(0, "WSP: Cannot parse Content-Range '%s'.",
02611 octstr_get_cstr(value));
02612 return -1;
02613
02614 warning:
02615 warning(0, "WSP: Cannot encode Content-Range '%s'.",
02616 octstr_get_cstr(value));
02617 return -1;
02618 }
02619
02620 int wsp_pack_content_type(Octstr *packed, Octstr *value)
02621 {
02622
02623
02624 return pack_accept(packed, value);
02625 }
02626
02627 static int pack_expires(Octstr *packed, Octstr *value)
02628 {
02629 int ret;
02630
02631 ret = wsp_pack_date(packed, value);
02632
02633 if (ret < 0) {
02634
02635
02636
02637 wsp_pack_long_integer(packed, LONG_AGO_VALUE);
02638 ret = 0;
02639 }
02640
02641 return ret;
02642 }
02643
02644 static int pack_if_range(Octstr *packed, Octstr *value)
02645 {
02646 if (octstr_get_char(value, 0) == '"' ||
02647 (octstr_get_char(value, 0) == 'W' &&
02648 octstr_get_char(value, 1) == '/')) {
02649 return wsp_pack_text(packed, value);
02650 } else {
02651 return wsp_pack_date(packed, value);
02652 }
02653 }
02654
02655 static int pack_pragma(Octstr *packed, Octstr *value)
02656 {
02657 Octstr *nocache;
02658
02659 nocache = octstr_imm("no-cache");
02660 if (octstr_case_compare(value, nocache) == 0)
02661 wsp_pack_short_integer(packed, WSP_CACHE_CONTROL_NO_CACHE);
02662 else {
02663 Parameter *parm;
02664 Octstr *encoding;
02665
02666 encoding = octstr_create("");
02667 parm = parm_parse(value);
02668 pack_parameter(encoding, parm);
02669 wsp_pack_value(packed, encoding);
02670 octstr_destroy(encoding);
02671 parm_destroy(parm);
02672 }
02673
02674 return 0;
02675 }
02676
02677 static int pack_range(Octstr *packed, Octstr *value)
02678 {
02679 Octstr *bytes = octstr_imm("bytes");
02680 long pos;
02681
02682 if (octstr_ncompare(value, bytes, octstr_len(bytes)) != 0
02683 || is_token_char(octstr_get_char(value, octstr_len(bytes))))
02684 goto error;
02685
02686 pos = octstr_len(bytes);
02687 while (isspace(octstr_get_char(value, pos)))
02688 pos++;
02689
02690 if (octstr_get_char(value, pos) != '=')
02691 goto error;
02692 pos++;
02693
02694 for (;;) {
02695
02696
02697
02698 pos = pack_range_value(packed, value, pos);
02699 if (pos < 0)
02700 goto error;
02701
02702 while (isspace(octstr_get_char(value, pos)))
02703 pos++;
02704
02705 if (octstr_get_char(value, pos) != ',')
02706 break;
02707 pos++;
02708
02709 wsp_pack_short_integer(packed, WSP_HEADER_RANGE);
02710 }
02711
02712 return 0;
02713
02714 error:
02715 warning(0, "WSP: Cannot parse 'Range: %s'.",
02716 octstr_get_cstr(value));
02717 return -1;
02718 }
02719
02720
02721 int wsp_pack_retry_after(Octstr *packed, Octstr *value)
02722 {
02723 Octstr *encoded = NULL;
02724
02725 encoded = octstr_create("");
02726 if (isdigit(octstr_get_char(value, 0))) {
02727 octstr_append_char(encoded, RELATIVE_TIME);
02728 if (wsp_pack_integer_string(encoded, value) < 0)
02729 goto error;
02730 } else {
02731 octstr_append_char(encoded, ABSOLUTE_TIME);
02732 if (wsp_pack_date(encoded, value) < 0)
02733 goto error;
02734 }
02735 wsp_pack_value(packed, encoded);
02736
02737 octstr_destroy(encoded);
02738 return 0;
02739
02740 error:
02741 octstr_destroy(encoded);
02742 return -1;
02743 }
02744
02745
02746 static int convert_rfc2616_warning_to_rfc2068(int warn_code)
02747 {
02748 int i;
02749 struct {
02750 int rfc2616code;
02751 int rfc2068code;
02752 } code_transform[] = {
02753 { 110, 10 },
02754 { 111, 11 },
02755 { 112, 12 },
02756 { 113, 13 },
02757 { 199, 99 },
02758 { 214, 14 },
02759 { 299, 99 },
02760 { -1, -1 }
02761 };
02762
02763 for (i = 0; code_transform[i].rfc2616code >= 0; i++) {
02764 if (code_transform[i].rfc2616code == warn_code)
02765 return code_transform[i].rfc2068code;
02766 }
02767
02768 return warn_code;
02769 }
02770
02771 static int pack_warning(Octstr *packed, Octstr *value)
02772 {
02773 long warn_code = -1;
02774 Octstr *warn_agent = NULL;
02775 Octstr *warn_text = NULL;
02776 long pos;
02777 long start;
02778
02779 pos = octstr_parse_long(&warn_code, value, 0, 10);
02780 if (pos < 0 || warn_code < 0)
02781 goto error;
02782
02783 if (warn_code > 99) {
02784
02785
02786
02787
02788 warn_code = convert_rfc2616_warning_to_rfc2068(warn_code);
02789 }
02790
02791 if (warn_code > MAX_SHORT_INTEGER) {
02792 warning(0, "WSP: Cannot encode warning code %ld.", warn_code);
02793 return -1;
02794 }
02795
02796 while (isspace(octstr_get_char(value, pos)))
02797 pos++;
02798
02799 start = pos;
02800 while (pos < octstr_len(value) && !isspace(octstr_get_char(value, pos)))
02801 pos++;
02802
02803 if (pos > start)
02804 warn_agent = octstr_copy(value, start, pos - start);
02805
02806 while (isspace(octstr_get_char(value, pos)))
02807 pos++;
02808
02809 start = pos;
02810 pos += http_header_quoted_string_len(value, pos);
02811 if (pos > start)
02812 warn_text = octstr_copy(value, start, pos - start);
02813
02814 if (warn_agent == NULL && warn_text == NULL) {
02815
02816 wsp_pack_short_integer(packed, warn_code);
02817 } else {
02818
02819 Octstr *encoding = octstr_create("");
02820
02821 if (warn_agent == NULL)
02822 warn_agent = octstr_create("");
02823 if (warn_text == NULL)
02824 warn_text = octstr_create("");
02825
02826 wsp_pack_short_integer(encoding, warn_code);
02827 wsp_pack_text(encoding, warn_agent);
02828 wsp_pack_text(encoding, warn_text);
02829 wsp_pack_value(packed, encoding);
02830 octstr_destroy(encoding);
02831 }
02832
02833 octstr_destroy(warn_agent);
02834 octstr_destroy(warn_text);
02835 return 0;
02836
02837 error:
02838 warning(0, "WSP: Cannot parse 'Warning: %s'.",
02839 octstr_get_cstr(value));
02840 octstr_destroy(warn_agent);
02841 octstr_destroy(warn_text);
02842 return -1;
02843 }
02844
02845 void wsp_pack_separate_content_type(Octstr *packed, List *headers)
02846 {
02847 Octstr *content_type;
02848
02849
02850
02851 content_type = http_header_find_first(headers, "Content-Type");
02852
02853 if (content_type == NULL) {
02854 warning(0, "WSP: Missing Content-Type header in "
02855 "response, guessing application/octet-stream");
02856 content_type = octstr_create("application/octet-stream");
02857 }
02858 octstr_strip_blanks(content_type);
02859 wsp_pack_content_type(packed, content_type);
02860 octstr_destroy(content_type);
02861 }
02862
02863 int wsp_pack_list(Octstr *packed, long fieldnum, List *elements, int i)
02864 {
02865 long startpos;
02866 Octstr *element;
02867
02868 while ((element = gwlist_consume(elements))) {
02869 startpos = octstr_len(packed);
02870
02871 wsp_pack_short_integer(packed, fieldnum);
02872 if (headerinfo[i].func(packed, element) < 0) {
02873
02874 octstr_delete(packed, startpos,
02875 octstr_len(packed) - startpos);
02876
02877 }
02878 octstr_destroy(element);
02879 }
02880 return 0;
02881 }
02882
02883 static int pack_known_header(Octstr *packed, long fieldnum, Octstr *value)
02884 {
02885 List *elements = NULL;
02886 long startpos;
02887 long i;
02888
02889 octstr_strip_blanks(value);
02890
02891 startpos = octstr_len(packed);
02892
02893 for (i = 0; i < TABLE_SIZE(headerinfo); i++) {
02894 if (headerinfo[i].header == fieldnum)
02895 break;
02896 }
02897
02898 if (i == TABLE_SIZE(headerinfo)) {
02899 error(0, "WSP: Do not know how to encode header type %ld",
02900 fieldnum);
02901 goto error;
02902 }
02903
02904 if (headerinfo[i].allows_list == LIST)
02905 elements = http_header_split_value(value);
02906 else if (headerinfo[i].allows_list == BROKEN_LIST)
02907 elements = http_header_split_auth_value(value);
02908 else
02909 elements = NULL;
02910
02911 if (elements != NULL) {
02912 if (wsp_pack_list(packed, fieldnum, elements, i) < 0)
02913 goto error;
02914 } else {
02915 wsp_pack_short_integer(packed, fieldnum);
02916 if (headerinfo[i].func(packed, value) < 0)
02917 goto error;
02918 }
02919
02920 gwlist_destroy(elements, octstr_destroy_item);
02921 return 0;
02922
02923 error:
02924
02925 octstr_delete(packed, startpos, octstr_len(packed) - startpos);
02926 gwlist_destroy(elements, octstr_destroy_item);
02927 return -1;
02928 }
02929
02930 int wsp_pack_application_header(Octstr *packed,
02931 Octstr *fieldname, Octstr *value)
02932 {
02933 if (!is_token(fieldname)) {
02934 warning(0, "WSP headers: `%s' is not a valid HTTP token.",
02935 octstr_get_cstr(fieldname));
02936 return -1;
02937 }
02938
02939
02940
02941
02942
02943
02944
02945 if (octstr_str_compare(fieldname, "X-WAP.TOD") == 0) {
02946 wsp_pack_text(packed, fieldname);
02947 return wsp_pack_date(packed, value);
02948 }
02949
02950 wsp_pack_text(packed, fieldname);
02951 wsp_pack_text(packed, value);
02952 return 0;
02953 }
02954
02955 Octstr *wsp_headers_pack(List *headers, int separate_content_type, int wsp_version)
02956 {
02957 Octstr *packed;
02958 long i, len;
02959 int errors;
02960
02961 packed = octstr_create("");
02962 if (separate_content_type)
02963 wsp_pack_separate_content_type(packed, headers);
02964
02965 len = gwlist_len(headers);
02966 for (i = 0; i < len; i++) {
02967 Octstr *fieldname;
02968 Octstr *value;
02969 long fieldnum;
02970
02971 http_header_get(headers, i, &fieldname, &value);
02972
02973
02974 fieldnum = wsp_string_to_versioned_header(fieldname, wsp_version);
02975
02976 errors = 0;
02977
02978 if (separate_content_type && fieldnum == WSP_HEADER_CONTENT_TYPE) {
02979
02980 } else if (fieldnum < 0) {
02981 if (wsp_pack_application_header(packed, fieldname, value) < 0)
02982 errors = 1;
02983 } else {
02984 if (pack_known_header(packed, fieldnum, value) < 0)
02985 errors = 1;
02986 }
02987
02988 if (errors)
02989 warning(0, "Skipping header: %s: %s",
02990 octstr_get_cstr(fieldname),
02991 octstr_get_cstr(value));
02992
02993 octstr_destroy(fieldname);
02994 octstr_destroy(value);
02995 }
02996
02997
02998
02999
03000
03001
03002 return packed;
03003 }
03004
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.