| | 854 | int http_response_handle_cachable(server *srv, connection *con, time_t mtime) { |
| | 855 | if (con->http_status != 0) return 0; |
| | 856 | |
| | 857 | /* |
| | 858 | * 14.26 If-None-Match |
| | 859 | * [...] |
| | 860 | * If none of the entity tags match, then the server MAY perform the |
| | 861 | * requested method as if the If-None-Match header field did not exist, |
| | 862 | * but MUST also ignore any If-Modified-Since header field(s) in the |
| | 863 | * request. That is, if no entity tags match, then the server MUST NOT |
| | 864 | * return a 304 (Not Modified) response. |
| | 865 | */ |
| | 866 | |
| | 867 | /* last-modified handling */ |
| | 868 | if (con->request.http_if_none_match) { |
| | 869 | if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) { |
| | 870 | if (con->request.http_method == HTTP_METHOD_GET || |
| | 871 | con->request.http_method == HTTP_METHOD_HEAD) { |
| | 872 | |
| | 873 | /* check if etag + last-modified */ |
| | 874 | if (con->request.http_if_modified_since) { |
| | 875 | char buf[64]; |
| | 876 | struct tm tm; |
| | 877 | size_t used_len; |
| | 878 | char *semicolon; |
| | 879 | |
| | 880 | strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime)); |
| | 881 | |
| | 882 | if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) { |
| | 883 | used_len = strlen(con->request.http_if_modified_since); |
| | 884 | } else { |
| | 885 | used_len = semicolon - con->request.http_if_modified_since; |
| | 886 | } |
| | 887 | |
| | 888 | if (0 == strncmp(con->request.http_if_modified_since, buf, used_len)) { |
| | 889 | con->http_status = 304; |
| | 890 | return 1; |
| | 891 | } else { |
| | 892 | /* convert to timestamp */ |
| | 893 | if (used_len < sizeof(buf) - 1) { |
| | 894 | time_t t; |
| | 895 | strncpy(buf, con->request.http_if_modified_since, used_len); |
| | 896 | buf[used_len] = '\0'; |
| | 897 | |
| | 898 | strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm); |
| | 899 | |
| | 900 | if (-1 != (t = mktime(&tm)) && |
| | 901 | t <= mtime) { |
| | 902 | con->http_status = 304; |
| | 903 | return 1; |
| | 904 | } |
| | 905 | } else { |
| | 906 | log_error_write(srv, __FILE__, __LINE__, "ss", |
| | 907 | con->request.http_if_modified_since, buf); |
| | 908 | |
| | 909 | con->http_status = 412; |
| | 910 | return 1; |
| | 911 | } |
| | 912 | } |
| | 913 | } else { |
| | 914 | con->http_status = 304; |
| | 915 | return 1; |
| | 916 | } |
| | 917 | } else { |
| | 918 | con->http_status = 412; |
| | 919 | return 1; |
| | 920 | } |
| | 921 | } |
| | 922 | } else if (con->request.http_if_modified_since) { |
| | 923 | char buf[64]; |
| | 924 | struct tm *tm; |
| | 925 | size_t used_len; |
| | 926 | char *semicolon; |
| | 927 | |
| | 928 | tm = gmtime(&(mtime)); |
| | 929 | strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S GMT", tm); |
| | 930 | |
| | 931 | if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) { |
| | 932 | used_len = strlen(con->request.http_if_modified_since); |
| | 933 | } else { |
| | 934 | used_len = semicolon - con->request.http_if_modified_since; |
| | 935 | } |
| | 936 | |
| | 937 | if (0 == strncmp(con->request.http_if_modified_since, buf, used_len)) { |
| | 938 | con->http_status = 304; |
| | 939 | return 1; |
| | 940 | } |
| | 941 | } |
| | 942 | |
| | 943 | return 0; |
| | 944 | } |
| 1352 | | |
| 1353 | | /* |
| 1354 | | * 14.26 If-None-Match |
| 1355 | | * [...] |
| 1356 | | * If none of the entity tags match, then the server MAY perform the |
| 1357 | | * requested method as if the If-None-Match header field did not exist, |
| 1358 | | * but MUST also ignore any If-Modified-Since header field(s) in the |
| 1359 | | * request. That is, if no entity tags match, then the server MUST NOT |
| 1360 | | * return a 304 (Not Modified) response. |
| 1361 | | */ |
| 1362 | | |
| 1363 | | /* last-modified handling */ |
| 1364 | | if (con->http_status == 0 && |
| 1365 | | con->request.http_if_none_match) { |
| 1366 | | if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) { |
| 1367 | | if (con->request.http_method == HTTP_METHOD_GET || |
| 1368 | | con->request.http_method == HTTP_METHOD_HEAD) { |
| | 1443 | |
| | 1444 | http_response_handle_cachable(srv, con, con->fce->st.st_mtime); |
| 1370 | | /* check if etag + last-modified */ |
| 1371 | | if (con->request.http_if_modified_since) { |
| 1372 | | char buf[64]; |
| 1373 | | struct tm tm; |
| 1374 | | size_t used_len; |
| 1375 | | char *semicolon; |
| 1376 | | |
| 1377 | | strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(con->fce->st.st_mtime))); |
| 1378 | | |
| 1379 | | if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) { |
| 1380 | | used_len = strlen(con->request.http_if_modified_since); |
| 1381 | | } else { |
| 1382 | | used_len = semicolon - con->request.http_if_modified_since; |
| 1383 | | } |
| 1384 | | |
| 1385 | | if (0 == strncmp(con->request.http_if_modified_since, buf, used_len)) { |
| 1386 | | con->http_status = 304; |
| 1387 | | } else { |
| 1388 | | /* convert to timestamp */ |
| 1389 | | if (used_len < sizeof(buf) - 1) { |
| 1390 | | time_t t; |
| 1391 | | strncpy(buf, con->request.http_if_modified_since, used_len); |
| 1392 | | buf[used_len] = '\0'; |
| 1393 | | |
| 1394 | | strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm); |
| 1395 | | |
| 1396 | | if (-1 != (t = mktime(&tm)) && |
| 1397 | | t <= con->fce->st.st_mtime) { |
| 1398 | | con->http_status = 304; |
| 1399 | | } |
| 1400 | | } else { |
| 1401 | | log_error_write(srv, __FILE__, __LINE__, "ss", |
| 1402 | | con->request.http_if_modified_since, buf); |
| 1403 | | |
| 1404 | | con->http_status = 412; |
| 1405 | | } |
| 1406 | | } |
| 1407 | | } else { |
| 1408 | | con->http_status = 304; |
| 1409 | | } |
| 1410 | | } else { |
| 1411 | | con->http_status = 412; |
| 1412 | | } |
| 1413 | | } |
| 1414 | | } else if (con->http_status == 0 && con->request.http_if_modified_since) { |
| 1415 | | char buf[64]; |
| 1416 | | struct tm *tm; |
| 1417 | | size_t used_len; |
| 1418 | | char *semicolon; |
| 1419 | | |
| 1420 | | tm = gmtime(&(con->fce->st.st_mtime)); |
| 1421 | | strftime(buf, sizeof(buf)-1, "%a, %d %b %Y %H:%M:%S GMT", tm); |
| 1422 | | |
| 1423 | | if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) { |
| 1424 | | used_len = strlen(con->request.http_if_modified_since); |
| 1425 | | } else { |
| 1426 | | used_len = semicolon - con->request.http_if_modified_since; |
| 1427 | | } |
| 1428 | | |
| 1429 | | if (0 == strncmp(con->request.http_if_modified_since, buf, used_len)) { |
| 1430 | | con->http_status = 304; |
| 1431 | | } |
| 1432 | | } |
| 1433 | | |